循环引用-智能指针的死穴之一

智能指针的实现思路也体现了C++基于对象的原则,对象应该为自己管理的资源负责,包括资源的分配与释放,而且最好将资源的释放与分配搞的自动化一点,典型的实现方法就是在构造函数里分配资源,在析构函数里释放资源,这样当其他程序员在使用这个对象时,该对象的资源问题几乎不用额外的操心,即优雅又方便

然后如此完美的东西,也有其不容忽视的地方,直接上代码:

// share_ptr.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "common_class.h"

class B;

class A{

private:
	typedef tr1::shared_ptr<B> Item_Type;
public:
	explicit A(){};
	virtual ~A(){};

public:
	void SetB(const Item_Type ptr_B){m_B = ptr_B;}
private:
	Item_Type m_B;
};

class B{

private:
	typedef tr1::shared_ptr<A> Item_Type;
public:
	explicit B(){};
	virtual ~B(){};
public:
	void SetA(const Item_Type ptr_A){m_A = ptr_A;}
private:
	Item_Type m_A;
};
int _tmain(int argc, _TCHAR* argv[])
{
	size_t count = 100000;
	getchar();//查看内存状态
	while(count--)
	{
		//new出来的A的引用计数此时为1
		shared_ptr<A> a(new A);
		//new出来的A的引用计数此时为1
		shared_ptr<B> b(new B);

		//B的引用计数增加为2
		a->SetB(b);
		//A的引用计数增加为2
		b->SetA(a);
	}
	getchar();//查看内存状态

	//b先出作用域,B的引用计数减少为1,不为0,所以堆上的B空间没有被释放,
	//且B持有的A也没有机会被析构,A的引用计数也完全没减少
	//a后出作用域,同理A的引用计数减少为1,不为0,所以堆上A的空间也没有被释放
	return 0;
}

两次查看内存资源状态结果

结果可知:内存增加了几乎20M,更何况我定义的两个对象本身不怎么占资源,如果内部维护了几个list,结果可想而知!

A和B都互相指着对方吼,“放开我的引用!“,“你先发我的我就放你的!”,于是悲剧发生了。

所以在使用基于引用计数的智能指针时,要特别小心循环引用带来的内存泄漏,循环引用不只是两方的情况,只要引用链成环都会出现问题。当然循环引用本身就说明设计上可能存在一些问题,如果特殊原因不得不使用循环引用,那可以让引用链上的一方持用普通指针(或弱智能指针weak_ptr)即可.

时间: 2024-11-09 05:02:20

循环引用-智能指针的死穴之一的相关文章

第22课 weak_ptr弱引用智能指针

一. weak_ptr的概况 (一)weak_ptr的创建 1. 直接初始化:weak_ptr<T> wp(sp); //其中sp为shared_ptr类型 2. 赋值: wp1 = sp; //其中sp为shared_ptr类型 wp2 = wp1; //其中wp1为weak_ptr类型 (二)常用操作 1. use_count():获取当前控制块中资源的强引用计数. 2. expired():判断所观测的资源是否失效(即己经被释放),即use_count是否为0. (1)shared_pt

智能指针的模拟实现shared_ptr 循环引用 定置删除器

auto_ptr与scoped_ptr的实现见本人的上篇博客. 三.shared_ptr shared_ptr的实现原理是通过引用计数来实现,只有当引用计数为1时才释放空间,否则只需将引用计数减1.拷贝和赋值将引用计数加1,具体代码如下: template <typename T> class SharedPtr { public: SharedPtr(); SharedPtr(T* ptr); SharedPtr(const SharedPtr<T>& ap); ~Sha

C++ 资源管理(RAII)--智能指针

1. 智能指针(Smart Pointer) i. 是存储指向动态分配(堆)对象指针的类 ii. 在面对异常的时候格外有用,因为他们能够确保正确的销毁动态分配的对象 iii. RAII类模拟智能指针,见备注 2. C++11提供了以下几种智能指针,位于头文件<memory>,它们都是模板类 i. std::auto_ptr(复制/赋值) ii. std::unique_ptr  c++11 iii.std::shared_ptr  c++11 iv.std::weak_ptr    c++11

boost智能指针之shared_ptr和weak_ptr

std::auto_ptr很多的时候并不能满足我们的要求,比如auto_ptr不能用作STL容器的元素.boost的smart_ptr中提供了4种智能指针和2种智能指针数组来作为std::auto_ptr的补充. shared_ptr<boost/shared_ptr.hpp>:使用shared_ptr进行对象的生存期自动管理,使得分享资源所有权变得有效且安全. weak_ptr<boost/weak_ptr.hpp>:weak_ptr 是 shared_ptr 的观察员.它不会干

c++智能指针的不断演化

RAII RAII资源分配即初始化,定义一个类来封装资源的分配和释放,在构造 函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放. 智能指针的引入: 由于return ,throw等关键字的存在,导致顺序执行流的错乱,不断的进行跳转,使开辟的空间 看似被释放,而实际上导致内存的泄露. 例如以下两个例子: void Test1() { int *p1 = new int(1); if (1) { return; } delete p1; } void DoSome

C++ Primer 学习笔记_56_STL剖析(十一)(原boost库):详解智能指针(unique_ptr(原scoped_ptr) 、shared_ptr 、weak_ptr源码分析)

注意:现在boot库已经归入STL库,用法基本上还和boost类似 在C++11中,引入了智能指针.主要有:unique_ptr, shared_ptr, weak_ptr. 这3种指针组件就是采用了boost里的智能指针方案.很多有用过boost智能指针的朋友,很容易地就能发现它们之间的关间: std boost 功能说明 unique_ptr scoped_ptr 独占指针对象,并保证指针所指对象生命周期与其一致 shared_ptr shared_ptr 可共享指针对象,可以赋值给shar

详解Boost库智能指针(shared_ptr &amp;&amp; scoped_ptr &amp;&amp; weak_ptr )

我们先来解释一下什么叫智能指针? 智能指针是利用RAII(在对象的构造函数中执行资源的获取(指针的初始化),在析构函数中释放(delete 指针):这种技法把它称之为RAII(Resource Acquisition Is Initialization:资源获取即初始化))来管理资源. 其本质思想是:将堆对象的生存期用栈对象(智能指针)来管理.也就是当new一个堆对象的时候,立刻用智能指针来接管,具体做法是在构造函数中进行初始化(用一个指针指向堆对象),在析构函数调用delete来释放堆对象.由

【C++】智能指针shared_ptr 定位删除器(仿函数)

智能指针shared_ptr 用引用计数实现看起来不错,但却存在问题. 1.引用计数更新存在着线程安全: 2.循环引用--使用一个弱引用智能指针(weak_ptr)来打破循环引用(weak_ptr不增加引用计数) 3.定置删除器和空间分配器 比如打开一个文件的关闭,用malloc开辟出来的空间,用引用计数实现会出现问题. 对改变引用计数时加锁可以解决引用计数更新存在着线程安全. 循环引用问题 #include<iostream> using namespace std; #include<

【C++】动态内存与智能指针

C++常见的内存分配方式有三种: 从静态存储区分配,这里主要是存储局部static对象,类的static成员以及定义在函数之外的变量: 从栈内存分配,这里主要是存储函数内的非static对象: 从堆内存动态分配 其中,静态存储区以及栈内存中的对象,都是由编译器自动创建和销毁,而堆内存中的对象都是由程序显示控制的,通常都是new创建delete销毁或者malloc创建free销毁.动态内存的管理非常棘手,如果动态地创建了对象却没有显式得销毁,就会发生内存泄漏:如果在还有指针引用的时候释放了内存就会