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

为何make_shared创建的对象在weak_ptr存活时仍会调用析构函数?

问题

理论上,make_shared()与直接构造shared_ptr的区别在于内存分配方式:make_shared()会一次性分配一块内存同时存放对象数据和引用控制块,而直接用shared_ptr<T>(new T)的方式会分别为对象和控制块分配两块独立内存。make_shared()的一个公认缺点是,只要还有weak_ptr存活,那整块包含对象和控制块的内存就无法被释放。但我编写的程序里,不管用哪种方式创建shared_ptr,输出结果都完全一致;而且在所有shared_ptr都调用reset()后,明明还有weak_ptr存活,对象的析构函数却被正常调用了。附上测试代码:

#include <iostream>
#include <memory>

class mc
{
    public:
      mc(int p):p_{p} {std::cerr<<"Constructor"<<std::endl;}
      ~mc() { std::cerr<<"Destructor"<<std::endl;}    
    private:
      int p_;    
};

std::weak_ptr<mc> wp3;

int main()
{
 
    auto sp=std::make_shared<mc>(4);
    auto sp2=sp;
    auto sp3{sp};
    wp3=std::weak_ptr<mc>{sp};
    
    sp2.reset();
    sp3.reset();
    sp.reset();
     
    for (int i =0;i< 5;i++) {std::cerr<<sp.use_count()<<std::endl;}   

    return 0;
}
解析
  • 你混淆了对象析构和内存释放两个概念:make_shared()的内存问题不是阻止对象析构,而是延迟整块内存的回收。当最后一个shared_ptr被reset或销毁时,对象的强引用计数降为0,对象的析构函数会立即执行——这和有没有weak_ptr存活完全无关。只有当最后一个weak_ptr也被销毁后,make_shared()分配的那块同时包含对象和控制块的内存才会被操作系统回收。而用shared_ptr<T>(new T)的方式,对象内存会在强引用计数为0时就被释放,控制块则要等到所有weak_ptr都销毁后才释放。
  • 你程序里的wp3是全局变量,会在main函数执行完毕后才销毁。但你看到的析构函数调用发生在main里所有shared_ptr reset之后,这完全符合预期,因为对象析构只由强引用计数决定。
  • 至于两种创建方式输出一致,是因为你的测试逻辑只检测了析构函数调用和shared_ptr的use_count()。use_count()返回的是强引用计数,weak_ptr的存在不会影响这个值,所以两种方式下输出自然相同。如果要验证内存释放的差异,需要借助内存分析工具(比如Valgrind),或者自定义内存分配器来跟踪内存的分配和释放时机。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:40:26