我们首先通过代码了解一下循环引用的情况
首先是shared_ptr的实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stdlib.h>
using namespace std;
//共享的智能指针
//使用引用计数
template <typename T>
class SharedPtr
{
public:
SharedPtr(T *p = NULL)//构造函数
:_p(p)
,_pCount(NULL)//不可以在此处初始化为1,如果p为NULL
{
if(NULL != _p)
{
_pCount = new int(1);
}
}
SharedPtr(const SharedPtr& sp)//拷贝构造函数
:_p(sp._p)
,_pCount(sp._pCount)
{
if(NULL != _pCount)//注意_pCount为NULL的情况,此时不能解引用,不用++
{
++(*_pCount);
}
}
SharedPtr& operator=(const SharedPtr& sp)
{
if(_p != sp._p)//注意自身赋值,有时候两个不同的对象但里面的的指针指向
//相同不能用(this != &sp)判断出来
{
if(NULL != _pCount)//被复制的对象本身为空//就没有为引用计数开辟空间
{
if(0 == --(*_pCount))//被赋值的对象自己管理一段空间,需要释放
{
delete _p;
delete _pCount;
_p = NULL;
_pCount = NULL;
}
}
_p = sp._p;//和其他对象共同管理
_pCount = sp._pCount;
if(NULL != sp._pCount)//注意判断赋值对象是否为空
{
++(*_pCount);
}
}
return *this;
}
T* operator->()//将原来的指针返回去,外边就可以用这个指针了
{
return _p;
}
~SharedPtr()
{
if (0 == --(*_pCount))
{
delete _p;
delete _pCount;
_p = NULL;
_pCount = NULL;
}
}
T *_p;
int *_pCount;
};
循环引用情况代码
#include<iostream>
#include<stdlib.h>
#include"SharedPtr.h"
using namespace std;
template <typename T>
struct Node
{
Node(const T& value)
:_value(value)
{}
~Node()
{}
SharedPtr<Node<T>> _ptr;
SharedPtr<Node<T>> _next;
T _value;
};
void FunTest()
{
SharedPtr<Node<int>> p1(new Node<int>(10));
SharedPtr<Node<int>> p2(new Node<int>(20));
p1->_next = p2;
p2->_ptr = p1;
}
int main()
{
FunTest();
system("pause");
return 0;
}
我们来分析一下造成循环引用的原因,上述代码形成的结果如下
p1 的后继指向p2,p2的前驱指向p1,p1等p2释放,p2等p1释放,这样就会造成最后p1 ,p2都没有释放,造成内存泄露。
boost库里引入了weak_ptr来解决了循环引用的问题。