博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【C++11】C++智能指针循环引用问题分析
阅读量:486 次
发布时间:2019-03-06

本文共 2153 字,大约阅读时间需要 7 分钟。

C++11中引入了三种智能指针,分别是shared_ptr、weak_ptr和unique_ptr

智能指针的作用

智能指针可以帮助我们管理动态分配的堆内存,减少内存泄漏的可能性

手动管理堆内存有引起内存泄漏的可能,比如这段代码

try {    int* p = new int;    // Do something    delete p;} catch(...) {    // Catch exception}

如果在执行Do something的时候发生了异常,那么程序就会直接跳到catch语句捕获异常,delete p这句代码不会被执行,发生了内存泄漏

我们把上面的程序改成

try {    shared_ptr
p(new int); // Do something} catch(...) { // Catch exception}

当执行Do something的时候发生了异常,那么try块中的栈对象都会被析构。因此代码中p的析构函数会被调用,引用计数从1变成0,通过new分配的堆内存被释放,这样就避免了内存泄漏的问题

循环引用问题

虽然智能指针会减少内存泄漏的可能性,但是如果使用智能指针的方式不对,一样会造成内存泄漏。比较典型的情况是循环引用问题,比如这段代码

class B; // 前置声明class A {public:    shared_ptr ptr;};class B {public:    shared_ptr ptr;};int main(){    while(true) {        shared_ptr pa(new A());        shared_ptr pb(new B());        pa -> ptr = pb;        pb -> ptr = pa;    }    return 0;}

这个程序中智能指针的引用情况如下图

在这里插入图片描述

上图中,class A和class B的对象各自被两个智能指针管理,也就是pa和pb引用计数都为2,为什么是2?

因为shared_ptr是一组指针指向一个实例,所以有几个shared_ptr指向类A,则类A就有几次引用。,class B对象同理。

在这种情况下,在main函数中一个while循环结束的时候,pa和pb的析构函数被调用,但是class A对象和class B对象仍然被一个智能指针管理,pa和pb引用计数变成1,于是这两个对象的内存无法被释放,造成内存泄漏,如下图所示

在这里插入图片描述

解决方法weak_ptr

std::weak_ptr

避免shared_ptr内存泄漏的利器。👈


smart pointer 三兄弟性格各异。unque_ptr是独来独往,shared_ptr是左拥右抱,而weak_ptr生来就不是为了单打独斗,了解之后你会发现他总是和shared_ptr出双入对。

weak_ptr为什么存在?

特性:

不可使用* 和 ->访问对象

被赋值,不会引起shared_ptr内部计数器值变化(我猜是它严格上来说不具备指针的能力---访问对象)

 

 所以,我们就可以用weak_ptr替代shared_ptr, 看👇例子。

#include 
#include
using namespace std;class B;class A{public: A() { cout << "A's constructor ..." << endl; } ~A() { cout << "A's destructor ..." << endl; } std::weak_ptr
weak_b;};class B{public: B() { cout << "B's constructor ..." << endl; } ~B() { cout << "B's destructor ..." << endl; } std::weak_ptr weak_a;};int main(){ std::shared_ptr aa = make_shared(); //aa->object A aa计数器 1 std::shared_ptr bb = make_shared(); //bb->object B bb计数器 1 aa->weak_b = bb; //计数器还是1哦 bb->weak_a = aa; //计数器还是1哦 return 0;}

 

object A & B都被成功析构(销毁)了。那么循环引用导致shared_ptr发生内存泄漏的问题迎刃而解!

原因是:weak_ptr不会增加shared_ptr的计数器,从而离开mian函数作用域时,shared_ptr aa & bb 计数器都 -1 ,成为0, 具备销毁条件,调用析构函数销毁自己和所指对象

至此,我们终于可以说weak_ptr具备避免内存泄漏的功能了!!!

转载地址:http://hhndz.baihongyu.com/

你可能感兴趣的文章