网上一般都是举个例子,说是循环引用,不易理解。
循环引用的本质是内存的管理问题。
引例
class A{
public:
xxx // 省略构造等
A a; // 出错
};
上面这种定义类的写法是错误的,在类A内定义一个A变量,定义A变量时还不知类A的具体内容和大小,肯定无法定义。
class A{
public:
xxx // 省略构造等
A * pa; // 可以
};
可以定义一个A的指针,因为指针固定是4字节大小的(32位)。
回到shared_ptr循环引用
一般的网上教程会给一个这样的例子
class B;
class A
{
public:
xxx
shared_ptr<B> pb;
};
class B
{
public:
xxx
shared_ptr<A> pb;
};
int main()
{
shared_ptr<A> pa(new A);
shared_ptr<B> pa(new B);
pa->pb = pb;
pb->pa = pa;
return 0;
}
- 理解循环引用,首先搞清楚变量的内存管理问题。
shared_ptr<A> pa(new A);
这一步会有两个主要的内存的管理步骤:
- 指针对象pa是一个局部变量,存放在
栈
。 - pa内部维护了一个new A出来的内存资源,存放在
堆
。
同样的对于 局部智能指针对象pb 也是如此。
栈
内的局部变量会被系统回收,而堆
内的智能指针对象却仍然无法自动回收,那么这个由智能指针管理的堆
区的引用计数永远无法为0。