C++ shared_ptr智能指针循环引用造成的内存泄露
概述
初开始看别人解释循环引用的时候,觉得理解了,但是当我使用到的时候突然就理解卡壳了,下面就说一下我的拨乱反正的思路历程。
关于shared_ptr循环引用的代码
#include <memory>
#include <iostream>
class TB;
class TA
{
public:
~TA(){
std::cout << "de TA" << std::endl;
}
std::shared_ptr<TB> tb;
};
class TB
{
public:
~TB(){
std::cout << "de TB" << std::endl;
}
std::shared_ptr<TA> ta;
};
int main()
{
{
auto a = std::make_shared<TA>(); // step1
auto b = std::make_shared<TB>(); // step2
a->tb = b; // step3
b->ta = a; // step4
// step 5
}
// step6
return 0;
}
我测试了代码,结果确实没有打印,也就是说这样的代码确实造成了内存泄露。
推导方法
-
Q: 智能指针的实现是基于引用计数的,那么智能指针又是如何实现引用计数的增加和减少呢?
-
A: 其实就是利用了类的析构函数,智能指针也是一个类,在给一个智能指针赋值的过程中就会对指向对象的引用加1;在智能指针超出作用域的时候智能指针对象就会析构,那么就会对指向对象的引用减1,如果减到0,智能指针就会删除指向对象。
-
所以我们分析引用增减的时候就是分析智能指针对象什么时候析构。
正确理解下的正确推导
- 在程序执行到 step1 的时候, 创建智能指针a,并赋值TA的对象,TA的对象引用加1;
- 在程序执行到 step2 的时候,创建智能指针b,并赋值TB的对象,TB的对象引用加1;
- 在程序执行到 step3 的时候,给a->tb赋值TB的对象,TB的对象引用加1;
- 在程序执行到 step4 的时候,给b->ta赋值TA的对象,TA的对象引用加1;
- 在程序执行到 step5 的时候,TA的对象应用为2,TB的对象应用为2;
- 在程序执行到 step6 的时候,b智能指针超出作用域开始析构,指向的TB对象引用减1;a智能指针超出作用域开始析构,指向的TA对象引用减1;
- 此时TA的对象应用为1,TB的对象应用为1;
错误理解
到step6的时候我潜意识里认为是 TB和TA对象开始析构,而不是智能指针的析构,造成了错误理解,所以这里特别提醒读者一定要区分开 指向对象 和 智能指针对象。
避免循环引用
那就是使用不增加引用的weak_ptr
更多
我的一个3D引擎DEMO项目也是使用了智能指针,在使用上有些心得,在此也分享给大家。