智能指针用法学习

news/2025/2/7 11:10:13/文章来源:https://www.cnblogs.com/BlueBlueSea/p/18203126

转自:https://blog.csdn.net/cpp_learner/article/details/118912592,chatgpt

1.介绍

智能指针就是帮管理动态分配的内存的,它会帮助我们自动释放new出来的内存,从而避免内存泄漏!使用智能指针可以自动调用对象的析构函数。

 例子:

class Test {
public:Test() { cout << "Test的构造函数..." << endl; }~Test() { cout << "Test的析构函数..." << endl; }int getDebug() { return this->debug; }private:int debug = 20;
};int main() { //Test *test = new Test;shared_ptr<Test> test(new Test);cout << "test->debug:" << test->getDebug() << endl;cout << "(*test).debug:" << (*test).getDebug() << endl;return 0;
}
//输出结果
Test的构造函数...
test->debug:20
(*test).debug:20
Test的析构函数... 

智能指针可以像普通指针一样使用-> 和*取内容,是因为 shared_ptr重载了这2个操作符函数:

1.1 get方法

获取智能指针托管的指针地址。但一般不这样用,直接用智能指针操作即可。

// 定义智能指针
shared_ptr<Test> test(new Test);Test *tmp = test.get();        // 获取指针返回
cout << "tmp->debug:" << tmp->getDebug() << endl;// 函数原型
_NODISCARD _Ty * get() const noexcept
{    // return wrapped pointerreturn (_Myptr);// 直接返回托管的指针
}

 

1.2 release方法

取消智能指针对动态内存的托管。

// 定义智能指针
shared_ptr<Test> test(new Test);Test *tmp2 = test.release();    // 取消智能指针对动态内存的托管
delete tmp2;    // 之前分配的内存需要自己手动释放// 函数原型
_Ty * release() noexcept
{    // return wrapped pointer and give up ownership_Ty * _Tmp = _Myptr; _Myptr = nullptr;// 将成员指针设置为空return (_Tmp);// 将指针返回外界,由外界来控制是否delete
}

 

1.3 reset方法

重置智能指针托管的内存地址,如果地址不一致,原来的会被析构掉。

// 重置
p.reset() ; 将p重置为空指针,所管理对象引用计数 减1
p.reset(p1); 将p重置为p1(的值),p 管控的对象计数减1,p接管对p1指针的管控
p.reset(p1,d); 将p重置为p1(的值),p 管控的对象计数减1并使用d作为删除器
p1是一个指针!// 交换
std::swap(p1,p2); // 交换p1 和p2 管理的对象,原对象的引用计数不变
p1.swap(p2);    // 交换p1 和p2 管理的对象,原对象的引用计数不变

 

2.shared_ptr 介绍

记录引用特定内存对象的智能指针数量,当复制或拷贝时,引用计数加1,当智能指针析构时,引用计数减1,如果计数为零,代表已经没有指针指向这块内存,那么我们就释放它。

class Person {
public:Person(int v) {this->no = v;cout << "构造函数 \t no = " << this->no << endl;}~Person() {cout << "析构函数 \t no = " << this->no << endl;}private:int no;
};
int main() { shared_ptr<Person> sp1;shared_ptr<Person> sp2(new Person(2));// 获取智能指针管控的共享指针的数量    use_count():引用计数cout << "sp1    use_count() = " << sp1.use_count() << endl;cout << "sp2    use_count() = " << sp2.use_count() << endl << endl;// 共享sp1 = sp2;cout << "sp1    use_count() = " << sp1.use_count() << endl;cout << "sp2    use_count() = " << sp2.use_count() << endl << endl;shared_ptr<Person> sp3(sp1); // 共同托管cout << "sp1    use_count() = " << sp1.use_count() << endl; // 可以打印引用计数值cout << "sp2    use_count() = " << sp2.use_count() << endl;cout << "sp2    use_count() = " << sp3.use_count() << endl << endl;return 0;
}// 输出结果
构造函数         no = 2
sp1     use_count() = 0
sp2     use_count() = 1sp1     use_count() = 2
sp2     use_count() = 2sp1     use_count() = 3
sp2     use_count() = 3
sp2     use_count() = 3析构函数         no = 2

 

2.1 使用make_shared构建对象

make_shared<类型>(构造函数参数列表);
shared_ptr<int> up3 = make_shared<int>(2); // 多个参数以逗号','隔开,最多接受十个
shared_ptr<string> up4 = make_shared<string>("字符串");
shared_ptr<Person> up5 = make_shared<Person>(9); //()内是构造函数的参数

会将对象指针和引用计数指针分配在一起,更高效。

3.注意事项

  • 在调用p.release()时会返回该指针,但不会释放p所指的内存,这时返回值就是对这块内存的唯一索引,如果没有使用这个返回值释放内存或是保存起来,这块内存就泄漏了。
  • 禁止delete 智能指针get 函数返回的指针。析构时造成重复释放
  • 禁止用任何类型智能指针get 函数返回的指针去初始化另外一个智能指针。具体解释:
//有问题的代码
std::shared_ptr<int> sp1(new int(10)); // 管理一个动态分配的整数
std::shared_ptr<int> sp4(sp1.get()); // 直接使用裸指针构造

sp1.get() 返回一个指向动态分配的整数的裸指针,但 shared_ptr 并不共享控制块和引用计数信息。如果 shared_ptr 通过裸指针构造,两个 shared_ptr 将独立管理同一个指针对象。这会导致两个 shared_ptr 在各自的生命周期结束时尝试释放相同的动态分配对象,从而造成双重释放问题,导致未定义行为(通常程序崩溃)。正确用法:

auto sp1 = std::make_shared<int>(10);
auto sp4 = sp1; // 正确: sp4 现在共享 sp1 的控制块和引用计数

通过拷贝构造函数来共享对象的所有权,确保引用计数正确管理对象的生命周期。

  • 不要定义指向智能指针的指针,这违背了智能指针的初衷。

 

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

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

相关文章

智能电网系统:构建未来能源的新篇章

随着科技的不断进步和全球能源需求的日益增长,智能电网系统已成为现代社会不可或缺的基础设施。它不仅能够提高能源利用效率,降低能源浪费,还能有效应对能源短缺和环境污染等问题。本文将围绕智能电网系统在能源管理、电力分配优化、需求响应以及分布式能源资源集成等方面的…

.Net6 web API (Log日志 数据表)

前沿 数据库连接 先下载 sql-server 这个数据库 下面这个是地址 https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads?SilentAuth=1&f=255&MSPPError=-2147217396&rtc=1然后下载安装 新建个查询 按钮输入 --基本表的创建 create table 学生 (学号 …

R语言空气污染数据的地理空间可视化和分析:颗粒物2.5(PM2.5)和空气质量指数(AQI)|附代码数据

原文链接:http://tecdat.cn/?p=23800 最近我们被客户要求撰写关于空气污染数据的研究报告,包括一些图形和统计输出。 由于空气污染对公众健康的不利影响,人们一直非常关注。世界各国的环境部门都通过各种方法(例如地面观测网络)来监测和评估空气污染问题 介绍 全球的地面…

C++——类

C++学习 类 一、定义 class 类名 {public: //外界可以直接访问或者调用private: //不能被外部所访问或调用, 只能被本类内部访问 };二、类的成员函数类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。类成员函数是类的一个成员,它可以操作…

R语言逻辑回归、决策树、随机森林、神经网络预测患者心脏病数据混淆矩阵可视化

全文链接:https://tecdat.cn/?p=33760 原文出处:拓端数据部落公众号 概述: 众所周知,心脏疾病是目前全球最主要的死因。开发一个能够预测患者心脏疾病存在的计算系统将显著降低死亡率并大幅降低医疗保健成本。机器学习在全球许多领域中被广泛应用,尤其在医疗行业中越来越受…

c++菱形继承、多态与类内存模型

目录1.菱形继承1.1.菱形继承的问题1.2.解决办法2.虚函数与多态2.1.普通函数不能实现多态2.2.虚函数(子类重写)+ 父类指向子类——实现多态2.3.多态原理3.c++内存模型4.参考 1.菱形继承 先看下面的例子,SheepTuo同时继承了Sheep和Tuo,而他们同时继承Animal类#include <io…

痞子衡嵌入式:从JLink V7.62开始优化了手动增加新MCU型号支持方法

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是JLink 7.62优化了手动增加新MCU型号支持方法。JLink 工具可以说是搞单片机开发的必备神器,JLink 包括一个硬件仿真器(分不同用途的 EDU/BASE/PLUS/WIFI/ULTRA+/PRO)和 PC 机上的驱动软件(从有迹可循的 20…

AnimationClip同步工具

用途:列出动画的第1帧与预制体GameObject当前值不同的,需要同步的可以手动同步 效果图 public struct ValueNotSameItem {public EditorCurveBinding curveBinding; //关联参数public AnimationCurve animCurve; //动画曲线public float kfValue; //动画曲线上第1帧的值publi…

鸿蒙HarmonyOS实战-Stage模型(开发卡片事件)

🚀一、开发卡片事件 HarmonyOS元服务卡片页面(Metaservice Card Page)是指在HarmonyOS系统中,用于展示元服务的页面界面。元服务是指一组提供特定功能或服务的组件,例如天气服务、音乐播放服务等。元服务卡片页面可以显示元服务的相关信息和操作选项,用户可以通过点击卡…

【论文阅读】FlexGraph: A Flexible and Efficient Distributed Framework for GNN Training

阅读思考问题: Please briefly describe how hierarchical dependency graphs are built in FlexGraph, and point out the specific stage in the NAU abstraction where this process takes place. 请简要描述在FlexGraph中如何构建分层依赖图,并指出在NAU抽象中的具体阶段…

N 年前,为了学习分库分表,我把 Cobar 源码抄了一遍

10 几年前,互联网产业蓬勃发展,相比传统 IT 企业,互联网应用每天会产生海量的数据。 如何存储和分析这些数据成为了当时技术圈的痛点,彼时,分库分表解决方案应运而生。 当时最流行的 Java 技术论坛是 javaeye ,有位淘宝的技术人员分享了一篇分库分表的文章 ,这篇文章,我…

4、Git之分支操作

4.1、分支的概述 在版本控制过程中,当需要同时推进多个任务时,可以为每个任务创建的单独分支。 虽然分支的底层实现是指针的引用,但是初学阶段可以将分支简单理解为副本,一个分支就是一个单独的副本。 使用分支,意味着从原来的主干上分离开,在分支上做的任何改动,在合并…