【C++】智能指针详解

一、从new和delete谈起

在C++中,可以使用new和delete关键字进行对象的创建和销毁,new一个对象实际上是在堆上分配内存,而new出来的对象也要自己用delete释放,从而回收内存,否则会造成内存的泄露。由程序员自己new来分配对象内存的方式成为动态分配。

其中有两个要点

  • new和delete需要成对使用,有new必然有delete,否则会导致内存泄漏,没有new分配的内存,不能使用delete来释放。
  • delete一块内存,只能delete一次,不可以delete多次,因为第一次delete之后,这块内存被回收会被分配给其他变量。可以在delete一个指针后将该指针设置为空ptr = nullptr。因为一个指针指向的内容即便被delete,该指针中依然保存着它所指向的那块动态内存地址,此时该指针被称为选空指针。如果此时将指针置空,则表示该指针不指向任何内存,这是一个良好的编程习惯

在使用动态分配时经常会有以下问题:

  • 内存泄漏:new了的对象再使用完后忘记delete导致内存一直被占用,相当于吃完饭不收盘子
  • 重复删除:对已经delete的对象进行再次delete,但是原内存空间被分配给了其他对象,导致回收到了其他的内存空间,相当于吃完饭把别人的盘子收了
  • 回收冲突:A和B均需要使用对象a,A使用完之后就顺手delete了a,但是B还需要使用a。相当于别人没吃完自己吃完,先把盘子收走了

总的来说,对内存进行管理依然是会让初学者头大的一个挑战,因此C++新标准中出现了智能指针。

二、智能指针

直接使用new一个对象的方式返回的是一个对象的指针,这个对象指针称为裸指针,这种指针功能强大使用灵活,但是需要全程负责维护,容易出错。在C++ 11中引入了新的指针——智能指针,智能指针对裸指针进行了包装,最突出的特性是智能指针能够自动释放所指向的对象。

C++标准库中规定了四种智能指针,分别是std::auto_ptr, std::unique_ptr, std:shared_ptr, std:weak_ptr,其中std::auto_ptr是C++ 98推出的,目前该智能指针已被std:unique_ptr取代,C++ 11中也明确弃用了该种智能指针。这三种指针其实都是类模板,可以将new获得的地址赋予给他们

  • shared_ptr是共享指针的概念,多个指针指向同一个对象,最后一个指针被销毁时,这个对象会被释放。
  • weak_ptr主要用于辅助shared_ptr工作
  • unique_ptr是一种独占式指针的概念,同一个时间内只能由一个指针指向该对象

2.1 shared_ptr

shared_ptr指针采用共享所有权来管理所指向对象的生存期,对象可以被多个shared_ptr指向,多个shared_ptr之间互相协作,从而确保只在不需要所指对象的时候才回收对象。shared_ptr的工作机制是引用计数,每一个shared_ptr指向相同的对象都会增加引用计数值,知道最后一个指向该对象的shared_ptr指针不再指向该对象的时候,才会析构对象

智能指针是一个类模板,使用尖括号规定指针指向的类型,使用形式如下

shared_ptr<指向的类型> 智能指针名// 样例
shared_ptr<string> p1; //一个指向string的智能指针

当然,智能指针也可以进行带初值的初始化

shared_ptr<int> pi(new int(100));

这是使用裸指针初始化智能指针的场景,但是还会遇到一些陷阱,因此shared_ptr模板中内置了make_shared函数进行初始化,是最安全并且更高效的初始化方法,它能够在动态内存(堆)中分配并且初始化一个对象,然后返回指向此对象的shared_ptr,使用方法如下:

shared_ptr<int> p2 = std::make_shared<int>(10);
shared_ptr<string> p3 = std::make_shared<string>(10, 'hello');

2.1.2 shared_ptr常规操作

1.引用计数的增加
每个shared_ptr会记录有多少个其他shared_ptr指向同样的对象
(1) 使用智能指针对另一个智能指针进行初始化

auto p6 = std::make_shared<int>(100);
auto p7 = p6;

(2)把智能指针作为实参往函数中传递

void myfunc(shared_ptr<int> ptmp){return;
}myfunc(p7);

这会增加指针引用数,当函数返回时减少
(3)作为函数返回值

shared_ptr<int> myfunc(shared_ptr<int> ptmp){return ptmp;
}p8 = myfunc(p7);

2.引用计数减少
(1)shared_ptr指向新对象的时候,引用计数减少
(2)局部智能指针离开其作用域,比如上面(2)中智能指针作为实参传递进函数时增加引用数,函数执行完毕后减少
(3)当一个shared_ptr引用技术变为0的时候,会自动释放自己管理的对象

3.常规操作
(1)use_count成员函数:返回有多少个智能指针指向某个对象
(2)unique成员函数,是否仅有一个智能指针指向某对象
(3)reset成员函数,不带参数时,pi置空,原对象引用计数-1;带参数则将该智能指针指向参数中的对象

*4.解引用
返回智能指针p指向的对象

5.get成员函数
p.get()用于返回智能指针p中保存的指针,小心使用,若智能指针释放了所指向的对象,则返回的指针所指的对象也会失效。

2.2 weak_ptr简介

weak_ptr是一个智能指针,这种智能指针指向一个由shared_ptr管理的对象,但是这种指针并不控制所指向对象的生存期,也不会改变shaed_ptr的引用计数。使用样例如下:

auto pi = make_shared<int>(100);
weak_ptr<int> piw(pi);

既然weak_ptr所指向的对象有可能不存在,那么waek_ptr是不能直接用于访问对象的,必须要使用一个叫做lock的成员函数,lock的功能是检查weak_ptr所指向的对象是否还存在,如果是,lock能够返回一个指向共享对象的shared_ptr,如果不存在,则返回一个空的shared_ptr

常用操作
1.use_count成员函数
获取该弱指针共享对象的其他shared_ptr数量,或者说强引用计数的数量

2.expired
若该指针的use_count为0,则返回true,反则返回false

3.reset成员函数
将该弱指针设置为空,不影响该对象的强引用数量,但是指向该对象的弱引用数量减1

4.lock
获取一个弱指针所指向的对象的shared_ptr

2.2.1 shared_ptr和weak_ptr的大小

weak_ptr和shared_ptr的尺寸都是裸指针的2倍大小,在x86平台下,一个裸指针的sizeof时4Bytes,因此weak_ptr和shared_ptr的大小都是8Bytes。其实这8个字节包含了2个裸指针,如图示:
在这里插入图片描述
其中第一个裸指针指向智能指针所指向的对象,第二个指针指向一个控制块,这个控制块中有:1.所指对象的引用计数 2.所指对象的弱引用计数 3.其他数据,比如自定义的删除器指针

2.3 unique_ptr简介和常规操作

2.3.1 unique_ptr简介

unique_ptr智能指针是一种独占式智能指针,同一个时刻,只有一个unique_ptr指针指向这个对象,当这个unique_ptr被销毁的时候,它所指向的对象也会被销毁。

1.常规初始化(unique_ptr和new配合)

unique_ptr<int> pi;
unique_ptr<int> pi2(new int(105));

2.make_unique函数
C++ 11中没有make_unique函数,但是C++ 14提供了这个函数
和常规的初始化相比,要优先选择make_unique函数,这能有更好的性能。但是如果使用make_unqiue的话,就不能使用删除器,因为make_unique不支持指定删除器的语法

unique_ptr<int> p1 = std::make_unique<int>(100);
auto p2 = std::make_unique<int>(200);

2.3.2 unique_ptr常用操作

1.unique_ptr不支持的操作

unique_ptr<string> ps1(new string("I Love China!));
unique_ptr<string> ps2(ps1);	// 不支持复制
unique_ptr<string> ps3 = ps1;	// 不支持复制
unique_ptr<string> ps4;
ps4 = ps1;	// 不支持赋值动作

unique_ptr不允许复制、赋值等操作,是一个只能移动不能复制的语义

2.移动语义
可以通过std:move将一个unique_ptr转移到其他的unique_ptr中

unique_ptr<string> ps1(new string("I Love China!));
unique_ptr<string> ps3 = std::move(ps1);	// 转移后ps3为空了,ps3指向原来的ps1所指

3.release成员函数
放弃对指针的控制权,切断智能指针和其所指向对象之间的联系。返回指针,将智能指针置空,返回的裸指针可以手工delete食坊,也可以用于初始化另一个智能指针,或者给另外一个智能指针赋值。

4.reset成员函数
当reset不带参数的时候,释放智能指针指向对象,并且将智能指针置空,当reset带参数时,释放智能指针指向原来的内存,让该智能指针指向新内存。

5.=nullptr
释放智能指针所指向的对象,并且将智能指针置空

6.指向一个数组

std::unique_ptr<int[]> ptr_arr(new int[10]);
ptr_arr[0] = 12;

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

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

相关文章

修改mf后缀的文件为zip(仅修改文件后缀,并非通过压缩解压的方式修改实际的文件)

仅修改文件后缀的python实现 1、以下代码仅简单的修改mf后缀的文件为zip&#xff0c;并非通过压缩解压的方式修改实际的文件。 2、执行后原有mf后缀的文件直接转换为zip的后缀&#xff0c;请注意备份。 &#xff08;注意&#xff1a;如果rar或者tar转成zip&#xff0c;请使用解…

机器学习/自主系统与亚当·斯密

人工智能中的机器学习和自主系统是当前科技领域的热门话题&#xff0c;它们与亚当斯密的经济学理论之间可能存在一些潜在的联系和启示。亚当斯密的经济学理论主要关注市场经济的运行和资源分配。他的核心观点是&#xff0c;通过市场机制的作用&#xff0c;个体追求自身利益的行…

前端框架(三件套)

学习网站 HTML 系列教程&#xff08;有广告&#xff09; HTML&#xff08;超文本标记语言&#xff09; | MDN (mozilla.org)&#xff08;英文不太友好&#xff09; 1.HTML5 & CSS3 1.1HTML5表格 <!DOCTYPE html> <html lang"en"> <head>…

李宏毅 机器学习与深度学习【2022版】 01

文章目录 一、基本概念二、深度学习内容总览三、预测YouTube播放量的模型1、假设一个含有未知参数的函数式2、根据Training Data定义一个 Loss3、最优化Optimization4、测试集验证模型性能5、线性模型特征维度提升6、非线性模型7、ReLU 四、深度学习概述1、Fully Connect Feedf…

边缘计算技术解决行业痛点,TSINGSEE智能分析网关V4技术特点与应用场景解析

一、行业背景 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;边缘计算硬件作为其核心组成部分&#xff0c;正逐步成为市场的新宠。这些硬件不仅提升了数据处理和分析的效率&#xff0c;还极大地降低了数据传输的延迟&#xff0c;为各行各业的智能化转型提…

Unity | 游戏开发中的优化思维

目录 ​​​​​​一、优化三板斧&#xff1a; 第1步&#xff1a;定标准 第2步&#xff1a;重数据 第3步&#xff1a;严测试 二、流程和性能的优化 1.定标准&#xff1a; 2.重数据&#xff1a; 三、交互和表现的优化 1.卡顿和延迟 2.手感硬 四、沟通和学习 ​​​​…

string模拟

本章准备对string模拟进行讲解&#xff0c;以下是string的学习网址&#xff1a; string - C Reference (cplusplus.com) string本质可以理解为储存char类型的顺序表&#xff0c;其中string的迭代器用一个char*就可以解决。所以string类成员变量如下&#xff1a; 这里用了一个命…

普通人如何抓住AI这个风口?

最强AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/ AI不仅仅是提升办公效率的利器&#xff0c;更是普通人目前最容易上手和变现的工具&#xff01;对于风口&#xff0c;大家应该都听…

使用yolov5实现目标检测简单案例(测试图片)

一、前置 测试这个案例之前需要安装一些前置的东西&#xff0c;如果已经安装的可以忽略&#xff0c;下面我给出我跟着做的一些很好的博客提供大家参考&#xff0c;因为我们主要目的还是实现yolov5的目标检测。 1、安装nvidia显卡驱动 可以参考&#xff1a;【Windows】安装NV…

Unified 阻抗控制 architecture、framework、approach

Unified 阻抗控制&#xff08;Unified Impedance Control&#xff09;作为一种控制策略&#xff0c;其architecture&#xff08;架构&#xff09;、framework&#xff08;框架&#xff09;和approach&#xff08;方法&#xff09;为&#xff1a; 一、Unified 阻抗控制 Archite…

京东数据编织

计算引擎是Hbase 中间计算结果的物化【就是存下来】 自动物化 在这里插入图片描述

Python自动化:解锁高效工作与生产力的密钥

在当今快节奏的数字时代&#xff0c;自动化已成为提升工作效率、优化流程、减少人为错误的不可或缺的工具。Python&#xff0c;作为一种功能强大、易于学习且应用广泛的编程语言&#xff0c;在自动化领域扮演着举足轻重的角色。无论是数据处理、Web自动化、软件测试&#xff0c…

SQL注入(原理、分类、union、POST注入)

目录 【学习目标、重难点知识】 【学习目标】 【重难点知识】 SQL注入简介 SQL注入原理 SQL注入类型 MySQL与SQL注入的相关知识 information_schema 数据库的结构 数据库查询语句 limit的用法 需要记住的几个函数 注释符号 SQL注入探测方法 SQL注入漏洞攻击流程…

ssh免密码登陆设置时Authentication refused: bad ownership or modes错误解决方法

0.环境&#xff1a; 三个节点&#xff1a;node1,node2,node3 1.问题描述&#xff1a; 配置好免密登录后&#xff0c;免密登录失效&#xff0c;还需要输入密码&#xff0c;如下图&#xff1a; 2.原因查找&#xff1a; 去查看系统的日志文件 使用命令&#xff1a; sudo tail …

基于Java语言的光伏监控系统+光伏项目+光伏储能+光伏运维系统

介绍 基于Java语言的光伏监控系统光伏发电系统光伏软件系统光伏监控系统源码光伏发电系统源码 软件架构 部分软件截图

Tmagic-editor低代码底层拖拽库Moveable示例学习

在前面咱们的自研低代码海报制作平台学习分享计划中分享了自己开发的基本拖拽组件&#xff0c;也只是做了最简单的基本实现。真要写产品&#xff0c;更多还是依赖相关的开源优秀库。 文章目录 参考基本拖拽基本缩放基本Scalable基本旋转基于原点的拖拽和旋转关于练习源码 参考 …

TCP详解(二)滑动窗口/流量控制

本文解释了TCP为何能保证数据传输的可靠性&#xff0c;以及如何保证整个网络的顺畅。 1 网络分层模型 这是一切的本质。网络被设计成分层的&#xff0c;所以网络的操作就可以称作一个“栈”&#xff0c;这就是网络协议栈的名称的由来。在具体的操作上&#xff0c;数据包最终形…

20. OTA流程 - 2

1. 概述 BES蓝牙方案自带OTA功能,支持SPP和BLE。 建议采用BLE的功能,因为苹果手机默认不支持SPP。 2. OTA框架 OTA时,耳机端需要先进入OTA状态 2.1 SPP升级

Nginx--代理与负载均衡(扩展nginx配置7层协议及4层协议方法、会话保持)

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、代理原理 1、反向代理产生的背景 单个服务器的处理客户端&#xff08;用户&#xff09;请求能力有一个极限&#xff0c;当接入请求过多时&#…

【网络安全】SSO登录过程实现账户接管

未经许可,不得转载。 文章目录 正文正文 登录页面展示了“使用 SSO 登录”功能: 经分析,单点登录(SSO)系统的身份验证过程如下: 1、启动SSO流程:当用户点击按钮时,浏览器会发送一个GET请求到指定的URL: /idp/auth/mid-oidc?req=[UNIQUE_ID]&redirect_uri=[REDI…