我在一个项目中使用了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;
}
这样,代码将可以正常执行并运行,我得到了预期的结果。
但是当我从继承中删除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;
}
然后导致崩溃。那么为什么public
在这里有所作为,为什么编译器没有给出警告/错误?
答案 0 :(得分:3)
根据https://en.cppreference.com/w/cpp/memory/enable_shared_from_this
enable_shared_from_this
的常见实现是保留对std::weak_ptr
的弱引用(例如this
)。std::shared_ptr
的构造函数检测到存在明确且可访问的(自C ++ 17起)enable_shared_from_this
基,并将新创建的std::shared_ptr
分配给内部存储的弱引用(如果尚未由其拥有)实况std::shared_ptr
(自C ++ 17起)。
如果继承是公共的,则在初始化ts
时,它将在enable_shared_from_this
基础子对象中“记录”它是TestShared
对象的所有者。以后调用getshared
时,将查询基础子对象,并创建一个与shared_ptr
共享所有权的新ts
对象。
如果继承不是公共的,则初始化ts
时,它不会“知道”有一个enable_shared_from_this
子对象需要写入。因此,在调用getshared
时,enable_shared_from_this
子对象不包含有关谁当前拥有该对象的任何信息。在C ++ 17中,这会导致异常。在C ++ 17之前,结果是不确定的。
答案 1 :(得分:3)
成为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 {...};
现在,B
希望能够进行shared_from_this
体操。但是D
是从那里秘密继承的。因此,D
与B
(并因此与B::shared_from_this
)的关系是私有的。也许D
使用B
的方式不会触发任何shared_from_this
的使用。
因此,如果D
不依赖B::shared_from_this
,并且如果B
只是D
的实现细节,那么如果有人放置{{ 1}}中的D
中?
您无法进行测试,不会导致像这样的误报。因此,如果无法访问shared_ptr
基类,那么可以尝试使用它的enable_shared_from_this
构造函数将不会尝试使用它。