问题背景
struct TestBase
{
virtual void reset(){
b = 0;
}
int b = 10;
};
struct Test : public TestBase
{
void reset() override {
TestBase::reset();
a = 0;
}
int a = 10;
};
template<typename T>
T* Construct_Fun()
{
int i_size = sizeof(T);
T* p_test_buffer = (T*)(new uint8_t[sizeof(T)]);
return p_test_buffer;
}
int main()
{
std::shared_ptr<Test> p_sh_test(Construct_Fun<Test>());
p_sh_test->reset(); // 错误,直接使用内存的话,类还没有初始化,只有一片裸内存
//std::shared_ptr<Test> p_sh_test = std::make_shared<Test>();
std::shared_ptr<TestBase> p_base = p_sh_test;
auto ppp = p_base.get();
auto page = std::dynamic_pointer_cast<Test>(p_base);
return 0;
}
问题1:
最开始是希望使用一块内存池来管理shared_ptr指向的内容,所以上面有个
std::shared_ptr<Test> p_sh_test(Construct_Fun<Test>());
的代码,后来发现虽然直接转可以,但是调用函数后出现司机错误
原因如代码中注释所示,申请了一块内存,但是这块内存是没有构造的,所以续表指针为未初始化状态,因此调用虚函数肯定会报错
问题2
另外一个问题,把上面的虚函数去掉,将reset设置成非虚函数,然后添加一个虚析构函数(必须是多态转换才能使用dynamic_pointer_cast,否则编译失败),然后调用reset是可以的,但是同样的道理,现在的虚函数指针还是未初始化的状态:
会发现转换到TestBase后,指针里面只维护了b的值和一个无效的续表指针,所以下面的转换dynamic_pointer_cast会失败
解决:
如果非要按照上面使用内存池来弄的话,那可以不使用虚函数,然后指针转换的时候,使用std::reinterpret_pointer_cast或者static_pointer_cast来解决