• C++11之智能指针



    为什么要使用智能指针

    在实际的 C++ 开发中,我们经常会遇到诸如程序运行中突然崩溃、程序运行所用内存越来越多最终不得不重启等问题,这些问题往往都是内存资源管理不当造成的。比如:

    1. 有些内存资源已经被释放,但指向它的指针并没有改变指向(成为了野指针),并且后续还在使用;
    2. 有些内存资源已经被释放,后期又试图再释放一次(重复释放同一块内存会导致程序运行崩溃);
    3. 没有及时释放不再使用的内存资源,造成内存泄漏,程序占用的内存资源越来越多。

    unique_ptr

    1. unique_ptr(独占型智能指针,不可以拷贝)
    2. unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。相比与原始指针unique_ptr用于其RAII的特性,使得在出现异常的情况下,动态资源能得到释放。
    3. unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)。
    4. unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。
    #include 
    #include 
    using namespace std;
    int main()
    {
        std::unique_ptr<int> p5(new int);
        *p5 = 10;
        // p 接收 p5 释放的堆内存
        int * p = p5.release();
        cout << *p << endl;
        //判断 p5 是否为空指针
        if (p5) {
            cout << "p5 is not nullptr" << endl;
        }
        else {
            cout << "p5 is nullptr" << endl;
        }
        std::unique_ptr<int> p6;
        //p6 获取 p 的所有权
        p6.reset(p);
        cout << *p6 << endl;;
        return 0;
    }
    
    输出:
    10
    p5 is nullptr
    10
    
    • 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

    share_ptr

    1. shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存
    2. 每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存
    3. shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁
    4. 智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。
    5. 不能将指针直接赋值 给一个智能指针,一个是类,一个是指针std::shared_ptr p4 = new int(1) //mistake
    6. 注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存
    7. 注意避免循环引用,shared_ptr的一个最大的陷阱是循环引用,循环引用会导致堆内存无法正确释放,导致内存泄漏

    创建shared_ptr的方式:

    /*
     * @Author: Phoenix_Z
     * @Date: 2022-09-02 17:22:45
     * @Last Modified by: Phoenix_Z
     * @Last Modified time: 2022-09-02 17:22:45
     * @Description: 
    */
    
    #include 
    #include 
     
    using namespace std;
    
    class Student
    {    
    public:
        char *m_name;
        Student(char *name) : m_name(name){};
        ~Student()
        {
            cout << "im:" << m_name << "," << "destroied" << endl;
        }
    
    };
     
    int main()
    {
        char * name = "james";
        shared_ptr<Student> p1 = make_shared<Student>(name);   //创建shared_ptr
        shared_ptr<Student> p2(p1);
        shared_ptr<Student> p3 = p2;
    
        Student *p = p3.get();       //将智能指针(类)指向的地址传递给指针
    
        cout << p->m_name << ","                                //指向同一块堆区,所以析构函数此时只调用一次
             << p1->m_name << ", "
             << p2->m_name << ", "
             << p3->m_name << "\n"
             << "p3 count:" << p3.use_count() << ", "           //use_count()计数
             << endl;
    
        p1.reset(new Student("kobe"));                          //此时p1改变了指向的地址
        cout << p1->m_name << endl;
        cout << "p1 after changed:" <<p1.use_count() << endl;
        cout << "p3 count after p1 changed:: " << p3.use_count() << endl;
    
        p2.reset();
        cout << "p3 count after p2 changed:" <<p3.use_count() << endl;
    
        return 0;
    }
    /*
    运行结果:
    james,james, james, james
    p3 count:3, 
    kobe
    p1 after changed:1
    p3 count after p1 changed:: 2
    p3 count after p2 changed:1
    im:james,destroied
    im:kobe,destroied
    */
    
    • 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
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    weak_ptr

    1. weak_ptr是用来监视shared_ptr的生命周期,它不管理shared_ptr内部的指针,它的拷贝的析构都不会影响引用计数,纯粹是作为一个旁观者监视shared_ptr中管理的资源是否存在,可以用来返回this指针和解决循环引用问题。
    2. 两个作用:
      作用1:返回this指针,上面介绍的shared_from_this()其实就是通过weak_ptr返回的this指针
      作用2:解决循环引用问题。
    #include 
    #include 
    using namespace std;
    int main()
    {
        std::shared_ptr<int> sp1(new int(10));
        std::shared_ptr<int> sp2(sp1);
        std::weak_ptr<int> wp(sp2);
        //输出和 wp 同指向的 shared_ptr 类型指针的数量
        cout << wp.use_count() << endl;
        //释放 sp2
        sp2.reset();
        cout << wp.use_count() << endl;
        //借助 lock() 函数,返回一个和 wp 同指向的 shared_ptr 类型指针,获取其存储的数据
        cout << *(wp.lock()) << endl;
        return 0;
    }
    
    输出:
    2
    1
    10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    fastadmin tp 安装使用百度富文本编辑器UEditor
    公众号添加菜单总是提示请输入http://或https://开头的公众号相关链接
    【状态估计】将变压器和LSTM与卡尔曼滤波器结合到EM算法中进行状态估计(Python代码实现)
    day48
    电动工具——电钻驱动方案设计
    Kafka常用参数
    不知道10年老电脑如何重装系统?其实很简单
    大数据学长面试京东面试题
    关于如何进行ChatGPT模型微调的新手指南
    解决IDEA中maven无法引进okhttp依赖
  • 原文地址:https://blog.csdn.net/weixin_45377028/article/details/126648976