目录

  • shared_ptr功能介绍
  • shared_ptr提供的接口
  • shared_ptr初始化
  • shared_ptr管理指针的构造和析构
  • shared_ptr获取原始指针
  • shared_ptr的线程安全
  • shared_ptr应用之enable_shared_from_this

写在前面的总结:
一个shared_ptr对象管理一个指针(new T,在堆空间),多个shared_ptr对象可以管理同一个指针,只有某个shared_ptr对象第一次初始化指针时才执行指针的构造函数,管理同一个指针的shared_ptr对象个数称为引用计数,这个引用计数保存在每个管理该指针的shared_ptr对象中,当引用计数为0时,这个指针执行析构函数释放;shared_ptr对象也可以管理空指针,此时引用计数为0。
shared_ptr做为函数参数传递时,函数运行期间引用计数加一,函数运行完后离开作用域,引用计数减一。

shared_ptr功能介绍

智能指针和普通指针用法相似,智能指针的本质是一个模板类,对普通指针进行了封装,通过在构造函数中初始化分配内存,在析构函数中释放内存,达到自己管理内存,不需要手动管理内存的效果,避免了忘记释放内存而导致的内存泄露。

shared_ptr 是C++11提供的一种智能指针类,可以在任何地方都不使用时自动删除相关指针,从而帮助彻底消除内存泄漏和悬空指针的问题。
它遵循共享所有权的概念,即不同的 shared_ptr 对象可以与相同的指针相关联,并在内部使用引用计数机制来实现这一点。
每个 shared_ptr 对象在内部指向两个内存位置:
1、指向对象的指针。
2、用于控制引用计数数据的指针。
共享所有权如何在参考计数的帮助下工作:
1、当新的 shared_ptr 对象与指针关联时,则在其构造函数中,将与此指针关联的引用计数增加1。
2、当任何 shared_ptr 对象超出作用域时,则在其析构函数中,它将关联指针的引用计数减1。如果引用计数变为0,则表示没有其他 shared_ptr 对象与此内存关联,在这种情况下,它使用delete函数删除该内存。

shared_ptr是以类模板的方式实现的,shared_ptr(其中 T 表示指针指向的具体数据类型)的定义位于头文件。

shared_ptr提供的接口

shared_ptr是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
shared_ptr的存储指针和引用计数指针是一一对应的,即shared_ptr里存的是存储指针,对应的引用计数指针就是对stored pointer的加一,因此shared_ptr在其内部,给每个资源都维护着一份计数,用来记录该份资源被几个对象共享。

shared_ptr初始化

构造函数初始化

///1.构造函数初始化
//传入空指针或什么都不传,构造出空智能指针,其初始引用计数方式为0
std::shared_ptr<int>  p0(nullptr);
printf("p0.use_count=%ld\n",p0.use_count());//p0.use_count=0//构造函数初始化,指向一个存有5这个int类型数据的堆内存空间
std::shared_ptr<int> p1(new int(5));
printf("p1=%p\n",&p1);//p1=0x7ffc24046f10
printf("p1=%d\n",*p1);//p1=5
printf("p1.use_count=%ld\n",p1.use_count());//1std::shared_ptr<int> p2(p1);//p1和p2都指向那个存有int型5的堆内存空间,堆内存的引用次数会加1
printf("p1.use_count=%ld\n",p1.use_count());//2
printf("p2.use_count=%ld\n",p2.use_count());//2std::shared_ptr<int> p3=p0;//P0为空,则P3也为空,其引用计数依然为0
printf("p3.use_count=%ld\n",p3.use_count());//0//补充
//可以把原始指针传参构造shared_ptr对象,此时原始指针没有new或没有初始化赋值,use_count都是1
int *p11 = new int;//如果没有=new int,下面p12.use_count还是1,但执行打印时会crash
//p11 = nullptr;//如果p11赋值为nullptr,下面p12.use_count还是1,但执行打印时会crash
std::shared_ptr<int> p12(p11);
printf("p12.use_count=%ld\n",p12.use_count());//1
printf("*p12=%d\n",*p12);//*p12=1345903632(原始指针new了,但没有初始化,则打印未知值)

std::make_shared 初始化

///2.std::make_shared 初始化
std::shared_ptr<int> p4 = std::make_shared<int>(); //1.定义一个空的智能指针
std::shared_ptr<int> p5= std::make_shared<int>(10);//2.创建指针,并明确指向
auto p6 = std::make_shared<std::vector<int>>();//3.auto关键字代替std::shared_ptr,p8指向一个动态分配的空vector<int>

reset初始化

///3.reset初始化
//调用reset(new xxx())重新赋值时,智能指针首先是生成新对象,然后将旧对象的引用计数减1(当然,如果发现引用计数为0时,则析构旧对象),然后将新对象的指针交给智能指针保管。
std::shared_ptr<int> p7(new int(20));
std::shared_ptr<int> p8(p7);
std::shared_ptr<int> p9(p7);
printf("p9.use_count=%ld\n",p8.use_count());//3
p7.reset(new int(21));//当为reset传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为1;其所指向的原堆内存引用计数减1
printf("p9.use_count=%ld\n",p8.use_count());//2
p9.reset();//当reset没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针
if(p9 == nullptr)printf("p10 == nullptr\n");//p10 == nullptr
printf("p9.use_count=%ld\n",p8.use_count());//1

shared_ptr管理指针的构造和析构

下面例子介绍shared_ptr是如何管理所指向指针(堆空间)的构造和析构的。

class book
{public:book(int v) {//构造函数value = v;std::cout << "cons book value=" <<value<< std::endl;}~book() {//析构函数std::cout << "desc book value=" <<value<< std::endl;}int value;
};{std::shared_ptr<book> b1(new book(100));//cons book value=100std::shared_ptr<book> b2(b1);//只增加了引用计数,没有新增构造book,use_count=2b2.reset(new book(200));//cons book value=200(新构造book200,原book100计数变为1)b1.reset(new book(300));//cons book value=300   desc book value=100(新构造book300,原book100引用计数变为0,执行析构)printf("end\n");//准备离开作用域
}

打印,shared_ptr初始化时如果生成了新的指针,则执行指针的构造函数,如果指向该指针的shared_ptr对象引用计数为0时,执行该指针的析构函数;
如果shared_ptr对象超出了作用域,则引用计数减1,引用计数为0时执行析构。

cons book value=100
cons book value=200
cons book value=300
desc book value=100
end
desc book value=200
desc book value=300

shared_ptr获取原始指针

智能指针提供了get()成员函数,用来执行显示转换,返回智能指针内部的原始指针。

std::shared_ptr<int> p10(new int(300));
int *pn = p10.get();
printf("pn=%d\n",*pn);//pn=300

shared_ptr的线程安全

1、shared_ptr不是线程安全的;
2、在多线程下,不能保证new出来一个对象一定能被放入shared_ptr中,也不能保证智能指针管理的引用计数的正确性;
3、同一个shared_ptr对象可以被多线程同时读取,不同的shared_ptr对象可以被多线程同时修改,但同一个shared_ptr对象不能被多线程直接修改;
4、在创建一个shared_ptr时,需要使用C++11提供的make_shared模板,make_shared创建shared_ptr只申请一次内存,避免了上述错误,也提高了性能,同时在读写操作时,需要加锁。

shared_ptr应用之enable_shared_from_this

C++11 开始支持 enable_shared_from_this,它是一个模板类,定义在头文件 ,其原型为:

template< class T > class enable_shared_from_this;

enable_shared_from_this 能让一个指针(假设其名为 t ,且已被一个 std::shared_ptr 对象 pt 管理)安全地生成其他额外的 std::shared_ptr 实例(假设名为 pt1, pt2, … ) ,它们与 pt 共享对象 t 的所有权。
若一个类 T 继承 std::enable_shared_from_this ,则会为该类 T 提供成员函数: shared_from_this 。
当 T 类型对象 t 被一个为名为 pt 的 std::shared_ptr 类对象管理时,调用 T::shared_from_this 成员函数,将会返回一个新的 std::shared_ptr 对象,它与 pt 共享 t 的所有权。

使用场景
1、当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。
2、在异步调用中,可能会使用到之前存在的变量,为了保证该变量在异步调用中一直有效,可以传递一个指向自身的share_ptr给异步函数,这样share_ptr所管理的对象就不会析构(引用计数至少>=1,保活)。

#include <iostream>
class Good : public std::enable_shared_from_this<Good> // 注意:继承
{public:Good(){std::cout << "Good::Good() called" << std::endl; }std::shared_ptr<Good> getptr() {return shared_from_this();}~Good() { std::cout << "Good::~Good() called" << std::endl; }
};
MainWindow::MainWindow(QWidget *parent)    : QMainWindow(parent)    , ui(new Ui::MainWindow)
{ui->setupUi(this);std::shared_ptr<Good> gp1(new Good());std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;//1std::shared_ptr<Good> gp2 = gp1->getptr();std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;//2
}

打印

Good::Good() called
gp1.use_count() = 1
gp1.use_count() = 2
Good::~Good() called

C++智能指针shared_ptr用法相关推荐

  1. 智能指针shared_ptr的用法

    智能指针shared_ptr的用法 2016-12-03 15:39 by jiayayao, 360 阅读, 0 评论, 收藏, 编辑 为了解决C++内存泄漏的问题,C++11引入了智能指针(Sma ...

  2. C++ 智能指针 shared_ptr、make_shared用法

    一.使用shared_ptr条件 C++版本11以上 需引入头文件 #include <memory> 否则编译会报错 error: 'shared_ptr' was not declar ...

  3. 智能指针的用法shared_ptr

    目录 智能指针 shared_ptr共享的智能指针 shared_ptr的基本用法 1.初始化 reset成员函数 make_shared swap()函数 2. 获取原始指针(get()) 3. 指 ...

  4. get方法报空指针_智能指针shared_ptr踩坑笔记

    平时写代码一直避免使用指针,但在某些场景下指针的使用还是有必要的.最近在项目中简单使用了一下智能指针(shared_ptr),结果踩了不少坑,差点就爬不出来了.痛定思痛抱着<Cpp Primer ...

  5. 智能指针shared_ptr的原理、用法和注意事项

    智能指针shared_ptr的原理.用法和注意事项 1 前言 2 shared_ptr原理 3 shared_ptr的基本用法 3.1 初始化 3.2 获取原始指针 4 智能指针和动态数组 4.1 c ...

  6. 智能指针shared_ptr

    如果有可能就使用unique_ptr,然后很多时候对象是需要共享的,因此shared_ptr也就会用得很多.shared_ptr允许多个指向同一个对象,当指向对象的最后一个shared_ptr销毁时, ...

  7. 智能指针shared_ptr的几个例子

    #include <string> #include <iostream> #include <memory> //智能指针定义在头文件memory中,例如shar ...

  8. C++智能指针shared_ptr、unique_ptr以及weak_ptr

    目录 shared_ptr类 shared_ptr和unique_ptr都支持的操作 shared_ptr独有的操作 make_shared函数 shared_ptr自动销毁所管理的对象 由普通指针管 ...

  9. 智能指针(shared_ptr、unique_ptr、weak_ptr)的使用

    智能指针的使用 一.shared_ptr 1.创建一个shared_ptr 2.shared_ptr的常用成员函数 reset成员函数的使用 3.==注意事项== 二.unique_ptr 1.uni ...

最新文章

  1. 20年的嵌入式开发经验总结
  2. 干货!MySQL 资源大全
  3. 史上最全最常用批处理260多个打包下载
  4. 中国500多名理工科研究生被美国拒签!美国「制裁清单」影响开始深入校园!...
  5. OpenGL 入门第一课 视窗以及三角形
  6. P1080 国王游戏
  7. Cordova自定义插件
  8. VC菜菜鸟-创建一个简单的多线程任务
  9. Zuul转发请求时HttpHostConnectException can‘t cast to ZuulException问题解决方法
  10. 【Spring 工厂】反转控制与依赖注入、Spring工厂创建复杂对象3种方式
  11. C语言之perror()与sterror()用法(十九)
  12. 预科计算机考试试题,少数民族预科计算机应用基础课程机考试题库的
  13. 轻松学,听说你还没有搞懂 Dagger2
  14. 解决Linux无法读写U盘中的NTFS问题
  15. 基于P2P的n2n部署测试方法
  16. 电赛笔记【数模转换原理】
  17. 保险精算--第8周作业
  18. 易语言网易云音乐登录post源码
  19. Python-一行输出列表元素
  20. 安卓(android)即时通讯

热门文章

  1. 巴西2014年世界杯徽标
  2. 6 JS 和 Jquery 删除标签元素
  3. jQuery 添加删除元素
  4. 自己开发了一个财神小童子合成
  5. mobilenetv1,v2,v3简要介绍
  6. Stable Diffusion 如何生成字体拼图
  7. Ubuntu安装 到移动硬盘或U盘--操作系统随身携带
  8. 天猫魔盒显示服务器响应错误,天猫魔盒网络连接异常 几招解决好这个问题
  9. 你练到什么程度了(J2EE)
  10. jstack-日志分析