如果继承不是公开的而不是出错,为什么 enable_shared_from_this 会崩溃

Nin*_*ina 2 c++ shared-ptr private-inheritance enable-shared-from-this

我在一个项目中使用了 shared_ptr。有一次,我不得不将原始指针存储为 void,然后在传递 void* 的回调中将其转换回其 shared_ptr 形式。但由于某种原因,代码不断崩溃。我不明白为什么,因为我没有收到任何编译器错误或警告。但我注意到,当我继承自时,std::enable_shared_from_this我并没有将其分配为公共继承。这就是导致崩溃的原因。

我写了一个示例代码,我只是想知道它为什么会发生。

#include <memory>
#include <iostream>

class TestShared : public std::enable_shared_from_this<TestShared>{
private:
    int32_t id;
public:
    TestShared(int32_t id){
        this->id = id;
    }
    std::shared_ptr<TestShared> getshared(){
        return shared_from_this();
    }
    int32_t getid(){
        return id;
    }
};

int main(){
    std::shared_ptr<TestShared> ts(new TestShared(0xFF));
    void* tsp = ts.get();
    std::shared_ptr<TestShared> tsn = ((TestShared*)tsp)->getshared();
    std::cout << std::hex << tsn->getid();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

所以该代码将执行并运行良好,我得到了预期的结果。

但是当我从继承中删除 public 时:

#include <memory>
#include <iostream>

class TestShared : std::enable_shared_from_this<TestShared>{
private:
    int32_t id;
public:
    TestShared(int32_t id){
        this->id = id;
    }
    std::shared_ptr<TestShared> getshared(){
        return shared_from_this();
    }
    int32_t getid(){
        return id;
    }
};

int main(){
    std::shared_ptr<TestShared> ts(new TestShared(0xFF));
    void* tsp = ts.get();
    std::shared_ptr<TestShared> tsn = ((TestShared*)tsp)->getshared();
    std::cout << std::hex << tsn->getid();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后它会导致崩溃。那么为什么public在这里有所不同,为什么编译器不给出警告/错误?

Nic*_*las 5

存在public很重要,因为shared_ptr系统需要访问enable_shared_from_this给定类型的基类。如果不能public从给定的类型访问它,它就不能这样做。

不可访问的基类没有警告/错误,因为系统无法知道您的代码是错误的。

即使是私有的shared_ptr,也可以使用可以“启用shared_from_this”的构造函数在概念上是可以的enable_shared_from_this。为什么?考虑以下:

class B : public enable_shared_from_this<B> {...};

class D : private B {...};
Run Code Online (Sandbox Code Playgroud)

现在,B期望能做shared_from_this体操。但D私下继承了它。SoDB(以及因此B::shared_from_this)的关系是私有的。也许D正在B以一种不会触发任何shared_from_this使用的方式使用。

因此,如果D不依赖于B::shared_from_this,如果B只是 的实现细节D,如果有人将 a 放入 aD中,为什么会出现错误shared_ptr

没有任何测试你能想出不会引起这样的误报。因此,如果enable_shared_from_this基类不可访问,那么shared_ptr可以尝试使用它的构造函数就不会尝试使用它。