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 创建的对象需要显式调用它们的析构函数。
  • 请不要将指针隐藏在 autotypedefusing 后面,不透明句柄除外。