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

调用std::shared_ptr方法时引用计数变化及对象异常销毁问题

你的理解完全正确!

你对this指针和std::shared_ptr引用计数关系的判断一点没错:this就是个裸指针,它的存在和任何shared_ptr的引用计数都没有关联。

在你的代码里,当深层递归触发myMap.insert({this,5})时,这里会隐式把this裸指针构造成一个新的std::shared_ptr<A>。这个新的shared_ptr根本不知道之前的pA已经在管理同一个对象——它会认为自己是第一个接管该对象生命周期的智能指针。所以当外层的pA出作用域销毁时,它会把引用计数减到0,直接销毁对象;而myMap里的那个shared_ptr就变成了悬空指针,指向已经被释放的内存,自然就出现了对象损坏的问题。

高效解决方案:继承std::enable_shared_from_this

C++标准库专门提供了解决这类问题的工具:std::enable_shared_from_this。它能让你从this指针获取到一个和当前管理该对象的shared_ptr共享引用计数的智能指针。具体操作分两步:

  1. 修改类A的定义,让它继承std::enable_shared_from_this<A>:
class A : public std::enable_shared_from_this<A> {
    // 原有的成员和方法...
    void DoSomething(void);
    A* Clone(void) const { return new A(*this); } // 注:原代码这里应该是*this(拷贝构造),不是this,可能是笔误
    static std::unordered_map<std::shared_ptr<A>,int> myMap{};
};
  1. 在插入map时,用shared_from_this()代替this:
if (condition)
    myMap.insert({shared_from_this(), 5});

shared_from_this()会返回一个std::shared_ptr<A>,它和当前管理该对象的所有shared_ptr(比如你的pA)共享引用计数。这样当pA出作用域时,引用计数只会减1,而myMap里的shared_ptr还持有一个引用,对象就不会被销毁了。

注意:shared_from_this()只能在已经被shared_ptr管理的对象上调用!也就是说,调用这个方法的对象必须已经被至少一个shared_ptr持有(比如你的场景里,DoSomething是被pA->DoSomething()调用的,pA就是管理当前对象的shared_ptr,所以完全安全)。如果在构造函数里调用shared_from_this(),会导致未定义行为(通常是抛出异常)。

为什么克隆能解决问题(但没必要)

你之前用克隆对象的方法能解决问题,本质是因为你创建了一个全新的对象,插入map的是管理这个新对象的shared_ptr——原pA的销毁只会影响原对象,和新对象无关。但这种方法带来的额外克隆开销,在类A数据复杂的情况下确实不划算,而enable_shared_from_this是零额外开销的标准解决方案。

设计层面的小建议

如果你的递归逻辑需要频繁把当前对象存入全局/静态容器,enable_shared_from_this是最贴合C++标准的设计选择。另外要注意:

  • 尽量避免用裸指针构造shared_ptr,除非你确定这个指针没有被其他shared_ptr管理;
  • 如果类的对象只会被shared_ptr管理,可以考虑把构造函数设为私有,只提供返回shared_ptr的工厂方法,从根源避免裸指针的误用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:46:11