• 【C++11】shared_ptr


    1. shared_ptr内存模型

    shared_ptr 包含了一个指向对象的指针和一个指向控制块的指针。每一个由 shared_ptr 管理的对象都有一个控制块,它除了包含强引用计数、弱引用计数之外,还包含了自定义删除器的副本和分配器的副本以及其他附加数据。
    在这里插入图片描述

    2. 尽量使用make_shared

    优势

    1. 避免代码冗余。
    2. 可编写异常安全代码。
    3. 提升性能。make_shared 只会进行一次内存分配,该内存单块既保存了T类型对象又保存与其相关联的控制块。而普通方式直接使用 new 操作符,除了为T类型对象分配一次内存,还要为与其关联的控制块再进行一次内存分配。

    在这里插入图片描述

    局限性

    1. 不允许自定义删除器
    2. 自定义内存管理的类,如重载了 new 操作符和 delete 操作符,不建议使用make_shared。因为:重载operator new和operator delete时,往往用来分配和释放该类精确尺寸(sizeof(T))的内存块;而make_shared创建的shared_ptr,是一个自定义了分配器(std::allocate_shared)和删除器的智能指针,由allocate_shared分配的内存大小也不等于上述的尺寸,而是在此基础上加上控制块的大小;
    3. 内存延迟释放问题。控制块和托管对象在同一内存块上分配,控制块是由 shared_ptr 和 weak_ptr 共享的,因此两者共同管理着这个内存单块。当强引用计数为 0 时,托管对象被析构(即析构函数被调用),但内存块并未被回收,只有等到最后一个 weak_ptr 离开作用域时,弱引用也减为 0 才会释放这块内存块。原本强引用计数减为 0 时就可以释放的内存, 现在变为了强引用计数和弱引用计数都减为 0 时才能释放。

    3. enable_shared_from_this模板类

    当我们需要一个类对象返回本身并且该类使用了 shared_ptr 智能指针时,需要使用该模板类。当我们使用智能指针管理资源时,必须统一使用智能指针,而不能再某些地方使用智能指针,某些地方使用原始指针,否则不能保持智能指针的语义,从而产生各种错误。

    #include <iostream>
    #include <memory>
    using namespace std;
    
    class Test
    {
    public:
    	// 析构函数
    	~Test()
    	{
    		cout << "Test Destructor." << endl;
    	}
    
    	// 获取指向当前对象的指针
    	shared_ptr<Test> GetObject()
    	{
    		return shared_ptr<Test>(this);
    	}
    };
    
    void test01()
    {
    	{
    		shared_ptr<Test> p(new Test());
    		shared_ptr<Test> q = p->GetObject();
    		cout << p.use_count() << endl;	// 1
    		cout << q.use_count() << endl;	// 1
    	}	// 异常
    }
    
    void test02()
    {
    	// 以上类似于
    	{
    		int *p = new int(10);
    		shared_ptr<int> p1(p);
    		shared_ptr<int> p2(p);
    	}	// 异常
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    // 使用enable_shared_from_this模板类解决问题
    #include <iostream>
    #include <memory>
    using namespace std;
    
    class Test : public enable_shared_from_this<Test>
    {
    public:
    	// 析构函数
    	~Test()
    	{
    		cout << "Test Destructor." << endl;
    	}
    	// 获取指向当前对象的指针
    	shared_ptr<Test> GetObject()
    	{
    		return shared_from_this();
    	}
    };
    
    void test01()
    {
    	{
    		shared_ptr<Test> p(new Test());
    		shared_ptr<Test> q = p->GetObject();
    		cout << p.use_count() << endl;	// 2
    		cout << q.use_count() << endl;	// 2
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    更深层次原理:enable_shared_from_this类模板中有一个弱指针 weak_ptr,这个弱指针能够监视 this 指针。在调用 shared_from_this 函数时,这个函数内部实际上是调用 weak_ptr 的 lock 方法。lock() 会让 shared_ptr 指针引用计数 + 1,同时返回这个 shared_ptr。

    4. shared_ptr线程安全问题

    为什么多线程读写 shared_ptr 要加锁?【陈硕】

    参考:https://blog.csdn.net/qq_38410730/article/details/105788724
    参考:https://blog.csdn.net/weixin_44517656/article/details/114195265

  • 相关阅读:
    电脑开不了机用U盘重装系统Win10教程
    web课程设计网页规划与设计 :DW旅游主题网页设计——凤阳智慧旅游官方-地方旅游网站模板html源码HTML+CSS+JavaScript
    未来3-5年最大的风口是什么?
    从哪里下载 Oracle database 11g 软件
    rocketmq消息发送源码学习
    springboot水环境检测系统的设计与实现毕业设计源码041446
    Python学习 - 异常处理
    pmp新考纲全真模拟题,提分敏捷+情景!
    苹果全球销量超越小米重回第二,荣耀回归国内手机市场第一梯队
    系统移植第5天作业
  • 原文地址:https://blog.csdn.net/weixin_46778443/article/details/125628748