You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何std::shared_ptr管理的对象会发生内存泄漏?

问题分析:shared_ptr循环引用导致的内存泄漏

代码示例

#include <iostream>
#include <memory>
#include <vector>

using namespace std;

class test : public enable_shared_from_this<test> {
    vector<shared_ptr<test>> vec;
public:

    void addvec()
    {
        vec.emplace_back(shared_from_this());
    }
    ~test() { cout << "destructing\n"; }
};


int main()
{
    auto sp = make_shared<test>();

    sp->addvec(); // when called, destructor is not invoked and
                  // LeakSanitizer reports a memory leak
}

问题描述

一个test对象由std::shared_ptr管理,调用addvec后,内部vector中存储了第二个std::shared_ptr实例(此时引用计数ref_count == 2)。但析构函数从未被调用,LeakSanitizer报告存在内存泄漏,请问这是为什么?

编译命令:g++ -g -fsanitize=leak c.cpp
GCC版本:12.2.1

原因解析

这是典型的shared_ptr循环引用问题,具体逻辑链如下:

  • main函数中的sp是指向test对象的shared_ptr,此时对象的引用计数为1。
  • 调用addvec后,test内部的vec容器存入了一个通过shared_from_this()生成的shared_ptr,该指针同样指向当前test对象,导致引用计数增加到2。
  • 当main函数执行完毕,sp被销毁,引用计数从2减到1。但此时test对象内部的vec还持有一个指向自身的shared_ptr,而vec是test对象的成员变量——只有test对象被销毁时,vec才会被销毁,进而释放它持有的shared_ptr。
  • 最终形成死锁:test对象要销毁,需要引用计数降到0;引用计数要降到0,需要vec里的shared_ptr被释放;vec要释放,又需要test对象先被销毁。循环依赖导致test对象永远无法被析构,内存因此泄漏。

解决方案

将内部持有指针的类型从shared_ptr<test>改为weak_ptr<test>即可解决问题。weak_ptr不会增加对象的引用计数,它仅作为对象的观察者,不会阻止对象被销毁。修改后的成员变量定义如下:

vector<weak_ptr<test>> vec;

调用addvec时无需额外修改,shared_from_this()返回的shared_ptr可以隐式转换为weak_ptr存入容器。这样当外部的sp销毁后,引用计数降到0,test对象会被正常析构,内部的vec也会随之销毁,不会形成循环引用。

内容的提问来源于stack exchange,提问作者Tootsie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:12:20