栗子

#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 循环引用问题以及解决办法相关推荐

  1. 关于在Webservice里使用LinqToSQL遇到一对多关系的父子表中子表需要ToList输出泛型而产生循环引用错误的解决办法!(转)...

    做一个网站时,有2个表,是一对多的关系 然后用生成器自动生成了一个LINQ To SQL类,然后查询子表时 由于子表里也有个父表的属性,所以当把查询的结果ToList时 又通过Webservice输出 ...

  2. 关于在Webservice里使用LinqToSQL遇到一对多关系的父子表中子表需要ToList输出泛型而产生循环引用错误的解决办法!...

    做一个网站时,有2个表,是一对多的关系 然后用生成器自动生成了一个LINQ To SQL类,然后查询子表时 由于子表里也有个父表的属性,所以当把查询的结果ToList时 又通过Webservice输出 ...

  3. 深入理解C++中的循环引用问题及解决方法

    循环引用问题在C++中是指当两个或多个对象互相持有对方的引用(通常是通过智能指针),导致它们的引用计数永远不会降为零,从而导致内存泄漏的情况.这种问题在使用shared_ptr时尤为突出,因为shar ...

  4. shared_ptr循环引用定置删除器

    shared_ptr虽然方便,但是它有着一个致命的缺陷就是循环引用问题,因为shared_ptr本身并没有能力解决这个问题,所以我们又引入了弱指针weak_ptr来辅助shared_ptr解决这个问题 ...

  5. 深入学习c++--智能指针(二) weak_ptr(打破shared_ptr循环引用)

    1. 几种智能指针 1. auto_ptr: c++11中推荐不使用他(放弃) 2. shared_ptr: 拥有共享对象所有权语义的智能指针 3. unique_ptr: 拥有独有对象所有权语义的智 ...

  6. nstimer循环引用_iOS中解决NSTimer循环引用问题

    NSTimer使用不当就会造成内存泄漏,比如常见的使用方法: //定义 @property (nonatomic, strong) NSTimer *timer; //实现 self.timer = ...

  7. nstimer循环引用_NSTimer定时器进阶——详细介绍,循环引用分析与解决

    引言 定时器:A timer waits until a certain time interval has elapsed and then fires, sending a specified m ...

  8. NSTimer定时器进阶——详细介绍,循环引用分析与解决

    引言 定时器:A timer waits until a certain time interval has elapsed and then fires, sending a specified m ...

  9. Linux GCC lib库相互引用,互相依赖(交叉引用)链接解决办法

    Linux GCC中,如果lib a依赖b,b又依赖a,链接的时候无论a放在前,还是b放在前,都会提示unrefrence. 解决办法就是: 链接的时候a链接两次,即: -la -lb -la

最新文章

  1. 终于有人把 SpringBoot 项目的Http客户端工具说清楚了!
  2. 【毕业求职季】-听说你想去大厂看学姐,带你看看网易java面经
  3. xshell 打开文件跳转到最后_xshell的快捷键(非常实用)
  4. 转发: Visual Studio 2005常用插件
  5. CG-CTF-Web-单身二十年
  6. PCB genesis自制孔点 Font字体实现方法
  7. leetcode —— 938. 二叉搜索树的范围和
  8. Go 面向对象编程(译)
  9. python的except之后还运行吗_python except异常处理之后不退出,如何解决异常继续执行...
  10. 东北大学oj平台python答案_东北大学大数据班R实训第三次作业
  11. 32个设计非常精美的国外网站作品范例(下篇)
  12. asp.net membership 配置错误
  13. JS 打印 data数据_用D3.js 十分钟实现字符跳动效果
  14. RoboWare Studio安装教程
  15. 【练习】新浪邮箱注册测试用例
  16. uniapp——ios端和android端微信分享,通过打开appStore和应用宝商店下载
  17. android显示大图片
  18. python locust在windows下的安装
  19. transformers中GLUE各个任务所用的评估方法
  20. 篱笆家装宝典之六——地板板材

热门文章

  1. lintcode:排颜色 II
  2. 用权值实现数据被抽取的概率
  3. S3 Texture Compression
  4. ajax传递json数组php,怎么通过ajax传送json数组到php,并通过php将数据插入数据库
  5. ubuntu java classpath_java – 如何为Ubuntu中的文件夹设置CLASSPATH变量
  6. java 乘法 位移_java 位移运算与乘法运算
  7. 新人问一般都用哪些 Linux 命令,我把这个扔了过去
  8. maven给默认中央仓库设置镜像为阿里云maven仓库并添加全局远程仓库
  9. Scala print语句格式打印
  10. redis缓存穿透、缓存击穿、缓存雪崩概念及解决方案