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

多继承下父类已继承std::enable_shared_from_this时子类的用法安全性

多继承场景下基于enable_shared_from_this<B>的shared_ptr<D>转换安全性分析

问题描述

假设类D多继承自A、B、C三个类,需要能够调用shared_from_this()获取自身的std::shared_ptr<D>。若其中父类B已继承std::enable_shared_from_this<B>,仅通过std::static_pointer_cast转换是否能安全为D提供shared_from_this功能?

示例代码:

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

class A 
{
public:
    void printX() { std::cout << x << std::endl; }
protected:
    A(int x) : x{ x } {}    
private:
    int x{ 3 };
};

class B : public std::enable_shared_from_this<B>
{
public:
    void printY() { std::cout << y << std::endl; }
protected:
    B(double y) : y{ y } {}
private:
    double y{ 5.89 };
};

class C
{
public:
    void printS() { std::cout << s << std::endl; }
protected:
    C(const std::string& s) : s{ s } {} 
private:
    std::string s{ "just a test" };
};

class D : public A, public B, public C
{
public:
    static std::shared_ptr<D> create(std::size_t n)
    {
        std::shared_ptr<D> dptr{ new D(1, 3.14, "parent node") };
        
        for (std::size_t i = 0; i < n; ++i)
            dptr->addChild(std::shared_ptr<D>{ new D(2, 7.7, "child node") });

        return dptr;
    }

    ~D()
    {
        std::cout << "~D()" << std::endl;
    }

    std::shared_ptr<D> getChild(std::size_t index) const
    {
        return children.at(index);
    }

    std::shared_ptr<D> getParent() const
    {
        return parent.lock();
    }

protected:
    D(int x, double y, const std::string& s)
        : A{ x }, B{ y }, C{ s } { }

    void addChild(const std::shared_ptr<D>& child)
    {
        child->parent = std::static_pointer_cast<D>(shared_from_this());
        children.push_back(child);
    }

private:
    std::weak_ptr<D> parent;
    std::vector<std::shared_ptr<D>> children;
};


int main()
{
    auto dptr = D::create(3);

    auto child1 = dptr->getChild(1);
    auto parent = child1->getParent();
    assert(parent == dptr);

    parent->printX();
    parent->printY();
    parent->printS();
}

分析与结论

当前写法的安全性

你测试的这段代码是安全的,原因如下:
当D对象被std::shared_ptr<D>托管时,B继承的enable_shared_from_this<B>内部的weak_ptr会被正确初始化——shared_ptr构造时会自动检测继承链中的enable_shared_from_this实例并完成关联。此时调用shared_from_this()得到的std::shared_ptr<B>指向D对象的B子对象,通过std::static_pointer_cast<D>转换是类型安全的,因为D是B的公有派生类,转换后的指针能正确指向完整的D对象。

潜在陷阱

虽然当前代码能正常运行,但存在几个需要注意的隐患:

  • 非公有继承限制:如果后续修改D继承B的方式为私有或保护,std::static_pointer_cast会编译失败,因为派生类到基类的转换路径不可访问。
  • 重复继承enable_shared_from_this风险:如果后续给D也添加enable_shared_from_this<D>继承,或者其他父类也引入enable_shared_from_this,会导致多个enable_shared_from_this实例共存,此时shared_from_this()调用会产生歧义,甚至导致内部weak_ptr关联错误,引发悬空指针或重复析构。
  • 裸指针构造shared_ptr的危险:如果用同一个D对象的裸指针分别构造std::shared_ptr<D>和std::shared_ptr<B>,enable_shared_from_this<B>的weak_ptr只会关联其中一个控制块,转换得到的shared_ptr<D>会和原shared_ptr<D>属于不同的引用计数体系,最终导致对象被重复析构。

更健壮的替代方案

推荐直接让D继承std::enable_shared_from_this<D>,即使B已经继承了enable_shared_from_this<B>。C++标准允许这种写法,因为每个enable_shared_from_this是独立的模板实例,不会产生二义性。此时D可以直接调用shared_from_this()获取std::shared_ptr<D>,无需类型转换,代码更清晰,也能避免上述所有陷阱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:19:56