欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

shared_ptr 循环引用问题以及解决办法

发布时间:2024/10/14 编程问答 49 豆豆
生活随笔 收集整理的这篇文章主要介绍了 shared_ptr 循环引用问题以及解决办法 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

栗子

#include <iostream> #include <memory>class CB; class CA { public:CA() { std::cout << "CA() called! " << std::endl; }~CA() { std::cout << "~CA() called! " << std::endl; }void set_ptr(std::shared_ptr<CB> &ptr) { m_ptr_b = ptr; }void b_use_count() { std::cout << "b use count : " << m_ptr_b.use_count() << std::endl; }void show() { std::cout << "this is class CA!" << std::endl; } private:std::shared_ptr<CB> m_ptr_b; };class CB { public:CB() { std::cout << "CB() called! " << std::endl; }~CB() { std::cout << "~CB() called! " << std::endl; }void set_ptr(std::shared_ptr<CA> &ptr) { m_ptr_a = ptr; }void a_use_count() { std::cout << "a use count : " << m_ptr_a.use_count() << std::endl; }void show() { std::cout << "this is class CB!" << std::endl; } private:std::shared_ptr<CA> m_ptr_a; };void test_refer_to_each_other() {std::shared_ptr<CA> ptr_a(new CA());std::shared_ptr<CB> ptr_b(new CB());std::cout << "a use count : " << ptr_a.use_count() << std::endl;std::cout << "b use count : " << ptr_b.use_count() << std::endl;ptr_a->set_ptr(ptr_b);ptr_b->set_ptr(ptr_a);std::cout << "a use count : " << ptr_a.use_count() << std::endl;std::cout << "b use count : " << ptr_b.use_count() << std::endl; }int main() {test_refer_to_each_other();return 0; }

结果

CA() called! CB() called! a use count : 1 b use count : 1 a use count : 2 b use count : 2

说明

上述结果说明,该 test_refer_to_each_other 执行完成之后,并没有释放掉 CA 和 CB 两个对象。因为起初定义完  ptr_a  和 ptr_b 时,只有 ① ③ 两条引用,然后调用函数 set_ptr 后又增加了 ② ④ 两条引用,当 test_refer_to_each_other 这个函数返回时,对象 ptr_a 和 ptr_b 被销毁,也就是 ① ③ 两条引用会被断开,但是 ② ④ 两条引用依然存在,每一个的引用计数都不为 0,结果就导致其指向的内部对象无法析构,造成内存泄漏。

解决办法

解决这种状况的办法就是将两个类中的一个成员变量改为 weak_ptr 对象。因为 weak_ptr 不会增加引用计数,使得引用形不成环,最后就可以正常的释放内部的对象,不会造成内存泄漏,比如将 CB 中的成员变量改为 weak_ptr 对象,代码如下:

class CB { public:CB() { cout << "CB() called! " << endl; }~CB() { cout << "~CB() called! " << endl; }void set_ptr(shared_ptr<CA>& ptr) { m_ptr_a = ptr; }void a_use_count() { cout << "a use count : " << m_ptr_a.use_count() << endl; }void show() { cout << "this is class CB!" << endl; } private:weak_ptr<CA> m_ptr_a; };

结果

CA() called! CB() called! a use count : 1 b use count : 1 a use count : 1 b use count : 2 ~CA() called! ~CB() called!

通过这次结果可以看到,CA 和 CB 的对象都被正常的析构了,引用关系如下图所示,流程与上一例子相似,但是不同的是 ④ 这条引用是通过 weak_ptr 建立的,并不会增加引用计数,也就是说 CA 的对象只有一个引用计数,而 CB 的对象只有 2 个引用计数,当 test_refer_to_each_other 这个函数返回时,对象 ptr_a 和 ptr_b 被销毁,也就是①③两条引用会被断开,此时CA对象的引用计数会减为0,对象被销毁,其内部的 m_ptr_b 成员变量也会被析构,导致 CB 对象的引用计数会减为0,对象被销毁,进而解决了引用成环的问题。

 

(SAW:Game Over!)

总结

以上是生活随笔为你收集整理的shared_ptr 循环引用问题以及解决办法的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。