一、背景

普通指针是指向某块内存区域地址的变量。如果一个指针指向的是一块动态分配的内存区域,那么即使这个指针变量离开了所在的作用域,这块内存区域也不会被自动销毁。动态分配的内存不进行释放则会导致内存泄漏。

如果一个指针指向的是一块已经被释放的内存区域,那么这个指针就是悬空指针。使用悬空指针会造成不可预料的后果。

如果我们定义了一个指针但未初始化使其指向有效的内存区域时,这个指针就成了野指针。使用野指针访问内存一般会造成段错误,即segmentation fault.

注:Segmentation fault:当程序试图访问未被分配的内存或无权访问的内存区域时,操作系统强制终止程序产生的错误。常见原因有:1.解引用空指针(上面所提到的);2.访问已释放的内存(悬空指针);3.数组越界;4.栈溢出(无限递归或过大的局部变量)。

使用智能指针可以有效避免上述错误的发生。智能指针是一个对象,它封装了一个指向另一个对象的指针。当智能指针对象离开了作用域后,会被自动销毁。销毁过程中会调用析构函数删除所封装的对象

二、unique_ptr

unique_ptr与它所管理的动态对象是一对一的关系,换言之,不能有两个unique_ptr对象同时指向相同的一块地址。

创建一个unique_ptr对象有两个方法:

unique_ptr<T> ptr1(new T(参数))
unique_ptr<T> ptr1= make_unique<T>(参数)

这里的T是一个类名。方法一:在构造函数中传入new分配的类对象。方法二:使用make_unique函数,它的参数是类T的构造函数的参数。

我们来看一个例子:

class Person
{
private:string name;int age;public:Person(string m_name, int m_age) :name(m_name), age(m_age){}~Person(){cout << "对象"<<name<<"被释放" << endl;}void check(){if (age < 18){cout << name << "的年龄为" << age << ",小于18岁" << endl;}else{cout << name << "的年龄为" << age << ",是成年人" << endl;}}
};int main()
{unique_ptr<Person>ptr1(new Person("比企谷", 17));unique_ptr<Person>ptr2 = make_unique<Person>("伊蕾娜", 18);ptr1->check();ptr2->check();return 0;
}

在main函数中我们定义了两个unique_ptr指针ptr1和ptr2,分别封装了两个动态创建的Person对象“比企谷”和“伊蕾娜”。由于智能指针重载了间接成员运算符和解引用运算符,它们会返回智能指针所包含对象的指针或者引用,因此可以像使用普通指针那样使用智能指针。例如上面的ptr1->check(),直接调用了Person对象的成员check.智能指针离开作用域后自动销毁,并调用析构函数释放指向的Person对象。

需要注意,下面三种情况也会删除当前所管理的对象:

ptr1=nullptr;
ptr1=move(ptr2);
ptr1.reset(new Person("雪之下雪乃",17));

上文说过,unique_ptr对所管理的资源具有独占性,所以unique_ptr的一个重要特性就是不能被拷贝也不能被赋值。

下面这段代码会在编译时出错:

unique_ptr<Person>ptr3=ptr2;

unique_ptr的类定义中没有这个拷贝构造函数。这样就保证了unique_ptr对象封装的指针不能和其它unique_ptr共用。但是上文提到了,我们可以对unique_ptr所管理对象的所有权进行转移,即:使用move函数。

unique_ptr<Person>ptr3=move(ptr2)

这样ptr3就拥有了原来ptr2所封装的指针的控制权。此时ptr2只包含了一个空指针,可以使用ptr3来访问它所封装的对象的成员。由于ptr2只包含了一个空指针,如果还使用ptr2访问成员,会出现segmentation fault.

再来看一个例子:

class energy
{
public:energy(){cout << "能量已充满" << endl;}~energy(){cout << "能量值为0" << endl;}
};unique_ptr<energy> fill()
{return unique_ptr<energy>(new energy());
}void consume(unique_ptr<energy>Energy)
{cout << "能量被消耗了" << endl;
}int main()
{cout << "开始" << endl;auto eng = fill();consume(eng);//错误的cout << "结束" << endl;
}

为什么consume(eng)是错误的?因为没有相应的拷贝构造函数,所以不能直接传值。正确方法如下:

consume(move(eng));

使用move函数将所有权转移给新的unique_ptr对象。

结果如下:

可以看到,这个engery对象被自动释放。

再来看一个例子:

struct Packet
{long m_id;char data[1000];Packet(long id) :m_id(id) {};
};struct Compare
{bool operator()(const Packet& a, const Packet& b){return a.m_id < b.m_id;}
};void sort_value_vector(int n)
{vector<Packet>vec;for (int i = 0; i < n; i++){vec.push_back(Packet(rand() % n));}sort(vec.begin(), vec.end(), Compare());
}

对于Packet这种较大的对象,排序意味着需要大量数据的移动复制。因为一个Packet对象大概是1008个字节,每交换两个Packet对象就需要复制1008字节的数据。我们可以将容器中的对象改成指针,这样排序的时候只涉及到指针值的复制。(交换两个指针只需复制4/8个字节)

struct Packet
{long m_id;char data[1000];Packet(long id) :m_id(id) {};
};struct Compare
{bool operator()(const Packet* pa, const Packet* pb){return pa->m_id < pb->m_id;}
};void sort_value_vector(int n)
{vector<Packet*>vec;for (int i = 0; i < n; i++){vec.push_back(new Packet(rand() % n));}sort(vec.begin(), vec.end(), Compare());
}

但是对于指针,需要单独进行维护。删除替换时需要释放不再使用的指针对象。不妨把容器中的指针换成unique_ptr,则不仅获得了普通指针的性能,还实现了内存资源的自动释放。

struct Packet
{long m_id;char data[1000];Packet(long id) :m_id(id) {};
};struct Compare
{template<template<typename> typename ptr>bool operator()(const ptr<Packet>&pa, const ptr<Packet>&pb){return pa->m_id < pb->m_id;}
};template<typename ptr>
void sort_value_vector(int n)
{vector<ptr>vec;for (int i = 0; i < n; i++){vec.push_back(new Packet(rand() % n));}sort(vec.begin(), vec.end(), Compare());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88577.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88577.shtml
英文地址,请注明出处:http://en.pswp.cn/web/88577.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTPS安全机制:从加密到证书全解析

目录 1.HTTPS是什么 2.加密是什么 3.HTTPS的加密过程 3.1对称加密 3.2非对称加密 4.引入证书 4.1"中间人"攻击 4.2 引入证书机制 4.3 理解数据签名 4.4 非对称加密 对称加密 证书认证 5.常见问题 5.1 Fiddler等抓包工具&#xff0c;为啥能解析HTTPS的数据…

2024年深度学习技术主要发展分析

摘要&#xff1a;深度学习作为人工智能领域的战略级技术&#xff0c;在2024年持续取得突破性进展&#xff0c;持续重构现代战争规则&#xff0c;成为大国军事智能化竞争的核心角力点。对2024年深度学习技术热门领域的主要发展进行了综合评述。研究了深度学习技术的发展现状&…

Swift 枚举:深入理解与高效使用

Swift 枚举:深入理解与高效使用 引言 Swift 枚举(Enum)是 Swift 编程语言中的一种基本数据类型,它允许我们将一组相关的值组合在一起。枚举在 Swift 中有着广泛的应用,从简单的数据分类到复杂的业务逻辑处理,枚举都能发挥巨大的作用。本文将深入探讨 Swift 枚举的原理、…

从大模型到云游戏,国鑫SY8108G-G4如何化身“全能AI引擎”?

当大模型参数量突破万亿级&#xff0c;传统服务器在散热枷锁与扩展瓶颈前举步维艰。国鑫全新推出的 SY8108G-G4 8U8卡AI服务器 &#xff0c;以颠覆性架构支持8张600W GPU全速并行&#xff0c;结合CPU-GPU直连、冗余电源和弹性扩展三大优势&#xff0c;为AI训练、生成式创作、数…

在多个DHCP服务器的网络环境中选择指定的DHCP服务

问题 学校有两个网络&#xff0c;我电脑网线插在同一个交换机的同一个接口上&#xff0c;有时候获取的是172.27开头的IP&#xff0c;有时候获取的是192.168开头的IP。 通常第一次开机获取的是172.27的IP&#xff0c;插拔网线或重启网络接口后会变为192.168的IP。 两个网络各有…

【Nginx】实测Nginx增加第三方主动式健康检查模块

一、环境说明系统版本&#xff1a;CentOS 7.9内核版本&#xff1a;3.10.0-1160.119.1Nginx版本&#xff1a;1.26.3第三方检测模块及版本&#xff1a;nginx_upstream_check_module&#xff08;v0.4.0&#xff0c;兼容nginx 1.20&#xff09;二、nginx安装部署2.1 下载检测模块目…

pytest中mark的使用

在pytest中&#xff0c;mark&#xff08;标记&#xff09;是用于对测试用例进行分类、筛选或附加元数据的重要功能。以下是其核心使用方法&#xff1a; 1. ‌基本标记定义与使用‌ ‌注册标记‌&#xff1a;在pytest.ini中预先定义标记&#xff08;避免运行时警告&#xff09;&…

STM32N6--NPU简单介绍

关键词&#xff1a;STM32N6、生物神经元、神经网络处理单元&#xff08;NPU&#xff09;、数据流处理 参考链接&#xff1a; RM0486 Reference manual STM32N647/657xx Arm-based 32-bit MCUsST_中文论坛【资料合集】STM32N6超全资料合集&#xff08;定期更新&#xff09;B站_…

一款开源免费、通用的 WPF 主题控件包

前言 今天大姚给大家分享一款开源免费&#xff08;MIT License&#xff09;、通用的 WPF 主题控件包&#xff1a;Rubyer WPF。 WPF介绍 WPF是一个强大的桌面应用程序框架&#xff0c;用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、数据绑定、样式和模板、动…

windows安装python环境以及对应编辑器的详细流程

windows安装python环境以及对应编辑器的详细流程 一、安装 Python 环境 步骤 1&#xff1a;下载 Python 安装包 访问 Python 官网&#xff1a;https://www.python.org/downloads/windows/选择最新稳定版本&#xff08;如 Python 3.12.x&#xff09;&#xff0c;点击 Download W…

高保真组件库:下拉多选

制作一个高保真的下拉多选需要具备多种交互事件。 拖拽一个文本框并命名为“下拉文本输入框”和一个向下的箭头组合在一起,外观上看起来是下拉组件。为了美观调整一些边框颜色、圆角、文字左边距等。 拖拽一个矩形作为下拉选项的容器,启动阴影xy都为0 制作下拉选项:拖拽一个…

sqli-labs靶场通关笔记:第1-4关 联合注入

第1关&#xff1a;单引号闭合1.这是第1关的界面&#xff0c;让我们以id作为参数输入&#xff0c;方式为数值&#xff0c;这里输入?id1看一下。2.显示了id1的用户名和密码。分析&#xff1a;在sql注入漏洞中&#xff0c;第一步是要寻找注入点&#xff0c;即可以输入参数的地方&…

和服腰封改造:3种解构主义造型的东方美学新解

和服腰封改造&#xff1a;3种解构主义造型的东方美学新解在东京原宿的小巷里&#xff0c;一场关于和服腰封的"温柔革命"正在悄然发生。年轻设计师们将传统宽腰带拆解重构&#xff0c;创造出既保留东方神韵又充满当代气息的造型艺术。正如一位新锐设计师所说&#xff…

什么是强化学习(RL)--3

如果reward大多数情况下都是0&#xff0c;只有少数是很大的值。这种情况下就是稀疏reward的问题。比如你要教机械手臂拴螺丝&#xff0c;只有最后把螺丝栓进去才可以&#xff0c;其余机械手臂的位置都不可以。额外的reward帮agent学习。reward shaping射击游戏cs,这个游戏中&am…

彩虹云商城全解源码系统|人工客服系统

核心升级亮点 人工客服系统&#xff1a;新增智能工单在线IM双模式多端同步&#xff1a;PCH5小程序APP四端数据实时互通支付升级&#xff1a;支持数字人民币收款安全加固&#xff1a;内置Web应用防火墙(WAF) 部署教程 ▶ B站视频教程 包含&#xff1a; 宝塔环境配置&#xf…

川翔云电脑:突破硬件极限,重构设计生产力范式

一、硬核配置&#xff1a;显存与算力的双重革命川翔云电脑提供从 RTX 2080 Ti 到 RTX 4090 Plus 的全系列 GPU 机型&#xff0c;其中旗舰级 4090 Plus 单卡配备48GB 超大显存&#xff0c;较传统 4090 显存翻倍&#xff0c;可流畅加载 1200 万面数的超复杂模型&#xff08;如《黑…

深入解析 TCP 连接状态与进程挂起、恢复与关闭

文章目录深入解析 TCP 连接状态与进程挂起、恢复与关闭一、TCP 连接的各种状态1. **LISTEN**&#xff08;监听&#xff09;2. **SYN_SENT**&#xff08;SYN 已发送&#xff09;3. **SYN_RECEIVED**&#xff08;SYN 已接收&#xff09;4. **ESTABLISHED**&#xff08;已建立&…

在mac m1基于llama.cpp运行deepseek

lama.cpp是一个高效的机器学习推理库&#xff0c;目标是在各种硬件上实现LLM推断&#xff0c;保持最小设置和最先进性能。llama.cpp支持1.5位、2位、3位、4位、5位、6位和8位整数量化&#xff0c;通过ARM NEON、Accelerate和Metal支持Apple芯片&#xff0c;使得在MAC M1处理器上…

多模态大语言模型arxiv论文略读(154)

Visual-Oriented Fine-Grained Knowledge Editing for MultiModal Large Language Models ➡️ 论文标题&#xff1a;Visual-Oriented Fine-Grained Knowledge Editing for MultiModal Large Language Models ➡️ 论文作者&#xff1a;Zhen Zeng, Leijiang Gu, Xun Yang, Zhan…

Python PDF处理库深度对比:PyMuPDF、pypdfium2、pdfplumber、pdfminer的关系与区别

Python PDF处理库深度对比&#xff1a;PyMuPDF、pypdfium2、pdfplumber、pdfminer的关系与区别前言1. 库的基本介绍1.1 PyMuPDF (fitz)1.2 pypdfium21.3 pdfplumber1.4 pdfminer2. 关系图谱3. 核心区别对比3.1 性能对比3.2 功能对比4. 代码示例对比4.1 基本文本提取PyMuPDFpypd…