dynamic_cast 关于多态 class 复制段错误
dynamic_cast on polymorphic class copy segfaults
以下代码片段在 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
。对象只能通过调用适当的构造函数来创建,例如初始化虚拟跳跃 table.
即使在您的上下文中,第二行也是错误的。它调用赋值运算符,正确地假设它的 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
。
- 通过 placement new 创建的对象需要显式调用它们的析构函数。
- 请不要将指针隐藏在
auto
、typedef
或 using
后面,不透明句柄除外。
以下代码片段在 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
。对象只能通过调用适当的构造函数来创建,例如初始化虚拟跳跃 table.
即使在您的上下文中,第二行也是错误的。它调用赋值运算符,正确地假设它的 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
。- 通过 placement new 创建的对象需要显式调用它们的析构函数。
- 请不要将指针隐藏在
auto
、typedef
或using
后面,不透明句柄除外。