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在这里有所不同,为什么编译器不给出警告/错误?
存在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私下继承了它。SoD与B(以及因此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可以尝试使用它的构造函数就不会尝试使用它。