C++11 标准保证字节对字节的副本对于 POD 类型始终有效。但是某些琐碎的类型呢?
这是一个例子:
struct trivial
{
int x;
int y;
trivial(int i) : x(2 * i) { std::cout << "Constructed." << std::endl; }
};
如果我要逐字节复制此结构,是否可以保证正确复制,即使它在技术上不是 POD?什么时候不能对对象进行字节复制?
C++11 标准保证字节对字节的副本对于 POD 类型始终有效。但是某些琐碎的类型呢?
这是一个例子:
struct trivial
{
int x;
int y;
trivial(int i) : x(2 * i) { std::cout << "Constructed." << std::endl; }
};
如果我要逐字节复制此结构,是否可以保证正确复制,即使它在技术上不是 POD?什么时候不能对对象进行字节复制?
是的,可以保证正确复制。
引用 FDIS,§3.9/2:
对于普通可复制 type 的任何对象(基类子对象除外)
T
,无论该对象是否拥有 type 的有效值T
,构成该对象的底层字节都可以复制到char
or的数组中unsigned char
。char
如果or的数组的内容unsigned char
被复制回对象,则该对象随后应保持其原始值。
和§3.9/3:
对于任何可简单复制的类型
T
,如果两个指针T
指向不同的T
对象obj1
和obj2
,其中既不是基类子对象obj1
也不obj2
是基类子对象,如果组成的基础字节obj1
被复制到obj2
,则obj2
随后应保持与 相同的值obj1
。
所以你要问的要求是,§3.9/9:
算术类型、枚举类型、指针类型、指向成员类型的指针
std::nullptr_t
以及这些类型的 cv 限定版本统称为标量类型。标量类型、POD 类、此类类型的数组以及这些类型的cv 限定版本统称为POD 类型。标量类型、可平凡复制的类类型、此类类型的数组以及这些类型的 cv 限定版本统称为可平凡复制类型。
和§9/6:
可简单复制的类是这样的类:
- 没有重要的复制构造函数,
- 没有重要的移动构造函数,
- 没有非平凡的复制赋值运算符,
- 没有非平凡的移动赋值运算符,并且
- 有一个微不足道的析构函数。
C++11 将 POD 类型的定义分解为更有用的类别,特别是“琐碎”和“标准布局”。您的示例是标准布局,并且可轻松复制,尽管构造函数阻止它完全微不足道。保证可以安全地按字节复制可简单复制的类型:
对于普通可复制类型 T 的任何对象(基类子对象除外),无论该对象是否拥有类型 T 的有效值,构成该对象的底层字节(1.7)都可以复制到 char 或unsigned char.40 如果将 char 或 unsigned char 数组的内容复制回对象,则该对象随后应保持其原始值。
So no, POD status is not required to be safely copied that way, but it is possible to identify the subset of non-POD types that can be.
如果标准声明它只为 POD 类型定义(我还没有详细检查 C++11 标准,所以我不知道你的论点是否正确(a))并且你这样做是为了非POD 类型,它不是定义的行为。时期。
在某些实现中,它可能在一天中的某些时间在行星对齐的某些环境中起作用。它可能在绝大多数时候都有效。如果您重视可移植性,那仍然不是一个好主意。
(a)经过更多调查,您的具体情况似乎没问题。标准的第 3.9/3 节(n3242 草案,但如果它与这个后期草案有很大变化,我会感到惊讶)指出:
对于任何可简单复制的类型 T,如果指向 T 的两个指针指向不同的 T 对象 obj1 和 obj2,其中 obj1 和 obj2 都不是基类子对象,如果构成 obj1 的底层字节被复制到 obj2 中,则 obj2 应随后保持相同值为 obj1。
第 9 节(在高层次上)定义了“可简单复制”的含义:
普通可复制类是这样的类:
- 没有非普通复制构造函数 (12.8),
- 没有非普通移动构造函数 (12.8),
- 没有非普通复制赋值运算符 (13.5.3, 12.8),
- 没有非平凡的移动赋值运算符(13.5.3、12.8),并且
- 有一个平凡的析构函数(12.4)。
参考部分更详细地介绍了每个区域,12.8
用于复制和移动类对象以及13.5.3
分配。