你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

c++11引入了三种智能指针

[复制链接]
gaosmile 发布时间:2020-7-6 22:48
很多人谈到c++,说它特别难,可能有一部分就是因为c++的内存管理吧,不像java那样有虚拟机动态的管理内存,在程序运行过程中可能就会出现内存泄漏,然而这种问题其实都可以通过c++11引入的智能指针来解决,相反我还认为这种内存管理还是c++语言的优势,因为尽在掌握。
c++11引入了三种智能指针:
  • std::shared_ptr
  • std::weak_ptr
  • std::unique_ptr

shared_ptr
shared_ptr使用了引用计数,每一个shared_ptr的拷贝都指向相同的内存,每次拷贝都会触发引用计数+1,每次生命周期结束析构的时候引用计数-1,在最后一个shared_ptr析构的时候,内存才会释放。
使用方法如下:

    1. <font style="background-color:rgb(255, 255, 255)"><font face="Tahoma"><font color="black">
    2. struct ClassWrapper {
    3.     ClassWrapper() {
    4.         cout << "construct" << endl;
    5.         data = new int[10];
    6.     }
    7.     ~ClassWrapper() {
    8.         cout << "deconstruct" << endl;
    9.         if (data != nullptr) {
    10.             delete[] data;
    11.         }
    12.     }
    13.     void Print() {
    14.         cout << "print" << endl;
    15.     }
    16.     int* data;
    17. };

    18. void Func(std::shared_ptr<ClassWrapper> ptr) {
    19.     ptr->Print();
    20. }

    21. int main() {
    22.     auto smart_ptr = std::make_shared<ClassWrapper>();
    23.     auto ptr2 = smart_ptr; // 引用计数+1
    24.     ptr2->Print();
    25.     Func(smart_ptr); // 引用计数+1
    26.     smart_ptr->Print();
    27.     ClassWrapper *p = smart_ptr.get(); // 可以通过get获取裸指针
    28.     p->Print();
    29.     return 0;
    30. }</font></font></font>
    复制代码
  • 智能指针还可以自定义删除器,在引用计数为0的时候自动调用删除器来释放对象的内存,代码如下:
  • std::shared_ptr<int> ptr(new int, [](int *p){ delete p; });
关于shared_ptr有几点需要注意:
• 不要用一个裸指针初始化多个shared_ptr,会出现double_free导致程序崩溃
• 通过shared_from_this()返回this指针,不要把this指针作为shared_ptr返回出来,因为this指针本质就是裸指针,通过this返回可能 会导致重复析构,不能把this指针交给智能指针管理。

  1. class A {
  2.     shared_ptr<A> GetSelf() {
  3.        return shared_from_this();
  4.        // return shared_ptr<A>(this); 错误,会导致double free
  5.     }  
  6. };
复制代码

  • 尽量使用make_shared,少用new。
  • 不要delete get()返回来的裸指针。
  • 不是new出来的空间要自定义删除器。
  • 要避免循环引用,循环引用导致内存永远不会被释放,造成内存泄漏。

    1. using namespace std;
    2. struct A;
    3. struct B;

    4. struct A {
    5.    std::shared_ptr<B> bptr;
    6.    ~A() {
    7.        cout << "A delete" << endl;
    8.   }
    9. };

    10. struct B {
    11.    std::shared_ptr<A> aptr;
    12.    ~B() {
    13.        cout << "B delete" << endl;
    14.    }
    15. };

    16. int main() {
    17.    auto aaptr = std::make_shared<A>();
    18.    auto bbptr = std::make_shared<B>();
    19.    aaptr->bptr = bbptr;
    20.    bbptr->aptr = aaptr;
    21.    return 0;
    22. }
    复制代码

上面代码,产生了循环引用,导致aptr和bptr的引用计数为2,离开作用域后aptr和bptr的引用计数-1,但是永远不会为0,导致指针永远不会析构,产生了内存泄漏,如何解决这种问题呢,答案是使用weak_ptr。
weak_ptr
weak_ptr是用来监视shared_ptr的生命周期,它不管理shared_ptr内部的指针,它的拷贝的析构都不会影响引用计数,纯粹是作为一个旁观者监视shared_ptr中管理的资源是否存在,可以用来返回this指针和解决循环引用问题。
  • 作用1:返回this指针,上面介绍的shared_from_this()其实就是通过weak_ptr返回的this指针,这里参考我之前写的源码分析shared_ptr实现的文章,最后附上链接。
  • 作用2:解决循环引用问题。

    1. struct A;
    2. struct B;

    3. struct A {
    4.    std::shared_ptr<B> bptr;
    5.    ~A() {
    6.        cout << "A delete" << endl;
    7.    }
    8.    void Print() {
    9.        cout << "A" << endl;
    10.    }
    11. };

    12. struct B {
    13.    std::weak_ptr<A> aptr; // 这里改成weak_ptr
    14.    ~B() {
    15.        cout << "B delete" << endl;
    16.    }
    17.    void PrintA() {
    18.        if (!aptr.expired()) { // 监视shared_ptr的生命周期
    19.            auto ptr = aptr.lock();
    20.            ptr->Print();
    21.       }
    22.    }
    23. };

    24. int main() {
    25.    auto aaptr = std::make_shared<A>();
    26.    auto bbptr = std::make_shared<B>();
    27.    aaptr->bptr = bbptr;
    28.    bbptr->aptr = aaptr;
    29.    bbptr->PrintA();
    30.    return 0;
    31. }
    32. 输出:
    33. A
    34. A delete
    35. B delete
    复制代码

unique_ptr
std::unique_ptr是一个独占型的智能指针,它不允许其它智能指针共享其内部指针,也不允许unique_ptr的拷贝和赋值。使用方法和shared_ptr类似,区别是不可以拷贝:

  1. using namespace std;

  2. struct A {
  3.    ~A() {
  4.        cout << "A delete" << endl;
  5.    }
  6.    void Print() {
  7.        cout << "A" << endl;
  8.    }
  9. };


  10. int main() {
  11.    auto ptr = std::unique_ptr<A>(new A);
  12.    auto tptr = std::make_unique<A>(); // error, c++11还不行,需要c++14
  13.    std::unique_ptr<A> tem = ptr; // error, unique_ptr不允许移动
  14.    ptr->Print();
  15.    return 0;
  16. }
复制代码

unique_ptr也可以像shared_ptr一样自定义删除器,使用方法和shared_ptr相同。
关于c++11的智能指针的使用就介绍到这里

收藏 评论0 发布时间:2020-7-6 22:48

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版