dynamic_cast在多态类复制段错误上



下面的代码片段导致dynamic_cast。有人能给我解释一下为什么会这样吗?

#include <cassert>
#include <cstdint>
uint8_t buffer[32];
class Top {
public:
virtual ~Top() = default;
};
template <typename T>
class Middle : public Top {
public:
void copy() {
// Create copy of class instance in buffer
auto memory{reinterpret_cast<T *>(buffer)};
*memory = *dynamic_cast<T *>(this);
// Upcast, works
Top * topPtr{memory};
assert(topPtr != nullptr);
// Downcast, causes segmentation fault, why?
auto bottomPtr{dynamic_cast<T *>(topPtr)};
}
};
class Bottom : public Middle<Bottom> {
};
int main() {
Bottom b;   
b.copy();
}

谢谢。

auto memory{reinterpret_cast<T *>(buffer)};
*memory = *dynamic_cast<T *>(this);

这是不正确的方法,您不能仅仅将一些字节解释为T。对象只能通过调用适当的构造函数来创建,例如初始化虚拟跳转表。

第二行即使在你的上下文中也是错误的。它调用赋值操作符,该操作符理所当然地假定它的this是一个活动对象。

正确的方法是使用放置new与正确对齐的存储,例如std::aligned_storage_t<sizeof(T),alignof(T)>

工作的例子:

#include <cstdint>
#include <cassert>
#include <type_traits>
#include <new>
class Top {
public:
virtual ~Top() = default;
};

template <typename T>
class Middle : public Top {
public:
void copy() {
std::aligned_storage_t<sizeof(T),alignof(T)> buffer;
// Create a new T object. Assume default construction.
auto* memory = new(&buffer)T();
// Copy the object using operator=(const T&)
*memory = *dynamic_cast<T *>(this);
// Upcast, works
Top * topPtr{memory};
assert(topPtr != nullptr);
// Downcast also works.
auto* bottomPtr{dynamic_cast<T *>(topPtr)};
// Using placement new requires explicit call to destructor.
memory->~T();
}
};
class Bottom : public Middle<Bottom> {
};
int main() {
Bottom b;   
b.copy();
}

  • 生命周期从一个构造函数调用开始,你不能绕过它,如果它需要参数,你必须传递它们。
  • operator=是复制对象的正确方法,除非你真的知道你在做什么,否则不要使用std::memcpy
  • 通过放置new创建的对象需要显式调用其析构函数。
  • 请不要在auto,typedefusing后面隐藏指针,不透明句柄除外。

最新更新