如何理解shared_ptr导致的循环引用问题

“循环引用”简单来说就是:两个对象互相使用一个 shared_ptr 成员变量指向对方。这样会引发一个问题,其中任何一个对象的引用计数都为2。析构时两个资源引⽤计数会减⼀,于是两者引⽤计数还是大于0,导致跳出函数时资源没有被释放(离开作用域时两个对象的析构函数没有被调⽤)
看下面的例子:

#include <memory>
using namespace std;
class father;
class son;
class father
{
public:
    shared_ptr<son> son;
public:
    ~father()  //析构函数
    {
        cout << "father distructor" << endl;  //删除对象
    }
};
class son
{
public:
    shared_ptr<father> father;
public:
    ~son()
    {
        cout << "son distructor" << endl;  //删除对象
    }

};

void test(father **f, son **s)
{
    shared_ptr<father> pfath(new father());
    shared_ptr<son> pson(new son());
    *f = pfath.get();
    *s = pson.get();
    pfath->son = pson;
    pson->father = pfath;
    cout << "pfath use_count:" << pfath.use_count() << endl; // father对象usecount:2
    cout << "pson use_count:" << pson.use_count() << endl; // sond对象usecount:2
}

int main()
{
    father *pfather;
    son *pson;
    test(&pfather, &pson); // test()结束以后析构函数并没有被调用
    cout << "pfath use_count:" << pson->father.use_count() << endl; // father对象usecount:1
    cout << "pson use_count:" << pfather->son.use_count() << endl; // sond对象usecount:2
    return 0;
}

输出

pfath use_count:2
pson use_count:2
pfath use_count:1
pson use_count:1

可以看到test()结束以后析构函数并没有被调用,会导致资源泄露。这显然违背了智能指针的初衷。

解决办法

使用weak_ptr 来打破循环引用,它与一个 shared_ptr 绑定,但却不参与引用计数的计算,不论是否有 weak_ptr 指向,一旦最后一个指向对象的 shared_ptr 被销毁,对象就会被释放。
修改上述代码:

class father
{
public:
    weak_ptr<son> son; // shared_ptr >> weak_ptr
public:
    ~father()  //析构函数
    {
        cout << "son distructor" << endl;  //删除对象
    }
};
class son
{
public:
    weak_ptr<father> father; // shared_ptr >> weak_ptr
public:
    ~son()
    {
        cout << "father distructor" << endl;  //删除对象
    }
};

运行输出:

pfath use_count:1
pson use_count:1
father distructor
son distructor
pfath use_count:0
pson use_count:0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容