shared_ptr造成的循环引用&&解决方法和原理(弱引用&&强引用)

 弱用指针的方式解决shared_ptr造成的循环引用防止内存泄漏!

《***》循环引用就是由于智能指针shared_ptr造成的,下面就是shared_ptr的使用造成循环引用的图解:

《****》举个例子来说下shared_ptr造成的循环引用:

(选题背景双向链表)

<span style="font-size:18px;">#include<memory>
#include<iostream>
using namespace std;

struct Node
{
	shared_ptr<Node> _pre;
	shared_ptr<Node> _next;

	~Node()
	{
		cout << "~Node():" << this << endl;
	}
	int data;
};

void FunTest()
{
	shared_ptr<Node> Node1(new Node);
	shared_ptr<Node> Node2(new Node);
	Node1->_next = Node2;
	Node2->_pre = Node1;

	cout << "Node1.use_count:"<<Node1.use_count() << endl;
	cout << "Node2.use_count:"<< Node2.use_count() << endl;
}

int main()
{
	FunTest();
	system("pause");
	return 0;
}</span>

执行结果:

(说明:shared_ptr的使用使得一块空间有两个对象管理,即头个结点的_next域和下一个指针共同管理,或者又头一个指针和第二个结点的_ptr域共同管理所以其_pCount=2)

针对上面出现的由于引用计数和管理空间的对象的个数导致空间不能释放的结果就是循环引用。

针对循环引用我们有三种解决方案:

《1》当只剩下最后一个引用的时候需要手动打破循环引用释放对象。

2       《2》当parent的生存期超过children的生存期的时候,children改为使用一个普通指针指向parent。

3       《3》使用弱引用的智能指针打破这种循环引用。虽然这三种方法都可行,但方法1和方法2都需要程序员手动控制

容易出错切不易操作。

*什么是强引用和弱引用?

一个强引用是指当被引用的对象仍活着的话,这个引用也存在(也就是说,只要至少有一个强引用,那么这个对象
就不会也不能被释放)。

boost::share_ptr就是强引用。

相对而言,弱引用当引用的对象活着的时候不一定存在。仅仅是当它自身存在的时的一个引用。

弱引用并不修改该对象的引用计数,这意味这弱引用它并不对对象的内存进行管理。

在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存 r

weak_ptr的出现就是为了辅助shared_ptr的工作,弥补shared_ptr的不足,解决shared_ptr造成的循环引用问题,而weak_ptr的这种解决方法也就是弱引用。

 

#include<memory>
#include<iostream>
using namespace std;

struct Node
{
	weak_ptr<Node> _pre;
	weak_ptr<Node> _next;

	~Node()
	{
		cout << "~Node():" << this << endl;
	}
	int data;
};

void FunTest()
{
	shared_ptr<Node> Node1(new Node);
	shared_ptr<Node> Node2(new Node);
	Node1->_next = Node2;
	Node2->_pre = Node1;

	cout <<"Node1.use_count:"<< Node1.use_count() << endl;
	cout <<"Node2.use_count:"<< Node2.use_count() << endl;
}

int main()
{
	FunTest();
	system("pause");
	return 0;
}<

  执行结果:

   *从上面的结果看,很明显,在用了智能指针weak_ptr后调用了析构函数,释放了空间,而shead_ptr则没有释放空间.

《*》在讲循环引用之前首先必须了解下什么是智能指针:

《**》下面就有关循环引用的两个指针shared_ptr和weak_ptr逐一分析下:

shared_ptr:

shared_ptr完成了你所希望的工作:他负责在不使用实例时删除由它指向的对象(pointee),并且它可以自由的共享它指向的对象(pointee)。

weak_ptr:

weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象。

weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己,但助手类enable_shared_from_this的shared_from_this会返回this的shared_ptr,只需要让想被shared_ptr管理的类从它继承即可

时间: 2024-10-01 20:46:40

shared_ptr造成的循环引用&&解决方法和原理(弱引用&&强引用)的相关文章

EntityFramework Model有外键时,Json提示循环引用 解决方法

正文之前先说两句,距离上篇博客已将近两个月,这方面的学习和探索并没有停止,而是前进道路上遇上了各种各样的问题,需要不断的整理.反思和优化,这段时间的成果,将在最近陆续整理发出来. 个人感觉国内心态太浮躁了,很少有能深入研究下去并将自己经验分享的人,可能很忙,也可能嫌麻烦.特别是面向新技术,尤其是在学习资料有限的情况下,愿意花费时间摸索和分享的人实在太少太少,遇到问题,搜索结果一抓一大把,但是往往都是转载,连最起码的自己验证都没有,结果就是以讹传讹,不仅对解决问题无用,反而容易产生误导.最近这段时

多线程下ArrayList类线程不安全的解决方法及原理

ArrayList类在多线程环境下是线程不安全的,在多线程读写情况下会抛出并发读写异常(ConcurrentModificationException): 1 import java.util.ArrayList; 2 import java.util.List; 3 import java.util.UUID; 4 5 public class NoSafeArrayList { 6 public static void main(String[] args) { 7 8 List<Strin

高DPI下界面错乱的解决方法和原理

来源: http://bbs.csdn.net/topics/370177760 我在win32 + c写的界面中解决办法,就是把字体的字号给固定了,这样做的结果就是,不管dpi是否有改变,界面中控件的文字的字号不变,就不会出现文字换行的情况. 但像菜单文字的字号就变大了,combobox(右三角),checkbox(选择框)变大一点点,显的有点不协调. 但至少不影响使用. 下面是判断当前系统的dpi,然后重置字体的字号. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

错误 1 error LNK2019: 无法解析的外部符号 __imp__pthread_create,该符号在函数 _main 中被引用 解决方法

晚上花几分钟在windows下测了下pthread的用法,出现错误 1 error LNK2019: 无法解析的外部符号 __imp__pthread_create,该符号在函数 _main 中被引用 经网上搜,反正都没解决,其中一个说引入#pragma comment(lib, "pthreadVC2.lib")后解决,但笔者遇到的不是这个原因,而是版本问题.可参考http://www.cnblogs.com/zhjh256/p/6364777.html解决.

编译lua5.3.2报错提示libreadline.so存在未定义的引用解决方法

从官网上下载5.3.2的源码后,make linux进行编译,提示报错: gcc -std=gnu99 -o lua lua.o liblua.a -lm -Wl,-E -ldl -lreadline /usr/local/lib/libreadline.so:对‘tputs’未定义的引用 /usr/local/lib/libreadline.so:对‘tgoto’未定义的引用 /usr/local/lib/libreadline.so:对‘tgetflag’未定义的引用 /usr/local/

ECSHOP程序登陆网站后台报错提示:此网页有重定向循环的解决方法

找到后台文件:admin/includes/init.php 打开 将以下内容: if (isset($_SERVER['PHP_SELF'])) {    define('PHP_SELF', $_SERVER['PHP_SELF']); } 修改成以下内容: if (isset($_SERVER['PHP_SELF'])) {     define( 'PHP_SELF' , $_SERVER['DOCUMENT_URI'] ); } 后台即可正常登录.

hashmap冲突的解决方法以及原理分析:

在Java编程语言中,最基本的结构就是两种,一种是数组,一种是模拟指针(引用),所有的数据结构都可以用这两个基本结构构造,HashMap也一样.当程序试图将多个 key-value 放入 HashMap 中时,以如下代码片段为例: HashMap<String,Object> m=new HashMap<String,Object>(); m.put("a", "rrr1"); m.put("b", "tt9&q

JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)

这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作是不同的域. 下表给出了相对 http://store.company.com/dir/page.html 同源检测的结果: 要解决跨域的问题,我们可以使用以下几种方法: 1.通过jsonp跨域[解决ajax跨域] 在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的

【转】JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)

这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作是不同的域. 下表给出了相对http://store.company.com/dir/page.html 同源检测的结果: 要解决跨域的问题,我们可以使用以下几种方法: 1.通过jsonp跨域 在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的.但是,在页面上引入不