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

为何使用enable_shared_from_this模板?通过成员函数生成shared_ptr的原因与问题

关于std::enable_shared_from_this<T>的疑问

最近接触到std::enable_shared_from_this<T>模板,它与Boost版本的实现一致。其示例代码如下:

#include <memory>
#include <cassert>

class Y: public std::enable_shared_from_this<Y> {
public:
    std::shared_ptr<Y> f() {
        return shared_from_this();
    }
};

int main() {
    std::shared_ptr<Y> p(new Y);
    std::shared_ptr<Y> q = p->f();
    assert(p == q);
    assert(!(p < q || q < p)); // p and q must share ownership
}

请问通过成员函数f()生成shared_ptr的原因是什么?这么做存在哪些问题?


为什么要通过shared_from_this()生成shared_ptr?

嘿,这个问题问到点子上了,核心是为了安全且正确地管理对象的生命周期,具体原因有这几点:

  • 避免双重析构的致命错误:如果直接在成员函数里写return std::shared_ptr<Y>(this),这个新创建的shared_ptr和外部的p会各自维护独立的引用计数。当它们都销毁时,会两次调用delete this,直接导致程序崩溃或者未定义行为。而shared_from_this()会复用当前对象已经关联的引用计数,让所有指向该对象的shared_ptr共享同一个计数,保证对象只会被析构一次。
  • 在成员内部安全获取自身的智能指针:很多场景下,类的成员函数需要把当前对象的指针传递给其他需要std::shared_ptr的接口(比如异步任务、回调注册),或者需要在函数内部持有自身的引用避免对象提前被销毁。用shared_from_this()能确保拿到的是和外部共享计数的智能指针,不会出现悬空指针的问题。
  • 遵循RAII设计原则:通过智能指针管理对象生命周期是RAII的核心实践,shared_from_this()让类内部也能符合这个原则,避免裸指针带来的各种生命周期管理风险。

使用enable_shared_from_this的潜在问题

虽然这个工具很实用,但也有不少需要注意的坑:

  • 必须先被shared_ptr持有才能调用:如果对象是栈上创建的(比如Y y; y.f();),或者刚用裸指针创建还没绑定到任何shared_ptr就调用shared_from_this(),会触发未定义行为——通常是抛出std::bad_weak_ptr异常,或者直接崩溃。这是因为enable_shared_from_this内部是通过一个weak_ptr来跟踪对象的,只有当对象被shared_ptr接管后,这个weak_ptr才会被正确初始化。
  • 可能引发循环引用:如果两个对象互相用std::shared_ptr持有对方,再加上其中一方通过shared_from_this()生成的指针,会导致引用计数永远无法降到0,对象永远不会被析构,造成内存泄漏。这种情况通常需要配合std::weak_ptr来打破循环。
  • 可读性与认知成本:如果团队成员不熟悉enable_shared_from_this的机制,可能会疑惑为什么不直接返回this或者直接构造shared_ptr,需要额外的注释或者团队共识来避免误用。
  • 复杂继承场景下容易出错:如果类的继承链中存在多重继承,或者派生类没有正确指定enable_shared_from_this的模板参数(比如派生类Z继承Y后,没有重新继承enable_shared_from_this<Z>),可能会导致引用计数混乱,出现未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:15:20