memcpy一个非POD对象

时间:2014-10-07 03:05:41

标签: c++

对于POD类型的对象,标准保证当您将对象的内容存储到数组中时 char或unsigned char,然后将内容memcpy回到你的对象中,该对象将保持其原始值。

现在请注意,对于非POD类型的对象没有这样的保证。所以我的问题是为什么会这样呢?

Source of the text above

3 个答案:

答案 0 :(得分:4)

简单可复制类的原因(C ++ 11主要使用概念普通类标准布局类而不是 POD )可以是memcpy与动态分配无关。当然,如果您尝试使用具有动态分配的类型的浅表副本,则会引发麻烦。但是你很可能有一个带有指针的类型,它在用户提供的构造函数中进行动态分配(只要它有一个默认的构造函数)并且有资格作为普通类

可以保证memcpy的实际原因是平易可复制(以及标准布局)类型需要占用连续的存储字节,而其他对象不是

N3690

  

1.8.5除非是比特字段(9.6),否则派生的最大对象应具有非零大小并占用一个或多个   存储字节。基类子对象可以具有零大小。一个简单可复制或标准布局的对象   type(3.9)应占用连续的存储字节。

答案 1 :(得分:2)

我不确定严格来说标准是否允许您将memcpy转换为char并再返回一个数组,尽管你肯定可以通过POD来解决这个问题。

但是当你开始研究C ++可以做的所有复杂事情时,事情变得更加模糊。请考虑以下事项:

struct ex1;

struct ex2
{
    ex2(std::unique_ptr<ex1> ptr) : member{ptr} {}
private:
    std::unique_ptr<ex1> member;
};

结构ex2是仅移动的,因为它有一个只移动的成员变量。那么如果我们使用memcpy来构造ex2实例的逐位相同副本会发生什么?我们最终得到两个对象,它们都认为它们拥有成员指针。当第二个被删除时会发生什么?你明白了。

答案 2 :(得分:2)

此类序列化失败的特定情况是具有虚拟成员的类型。如果一个类型有一个虚拟成员,那么它有一个vtable。该表将包含指向每个虚拟成员的实现的指针。

如果char数组中的序列化数据穿过进程边界(您通过网络发送它,或者将其写入磁盘并从另一个进程读回),那么您写出的vtable指针可能不再是有效,并且调用任何虚拟成员都会导致未定义的行为。