C ++ 11标准保证逐字节副本始终对POD类型有效。但是某些琐碎的类型呢?
以下是一个例子:
struct trivial
{
int x;
int y;
trivial(int i) : x(2 * i) { std::cout << "Constructed." << std::endl; }
};
如果我要逐字节地复制这个结构,它是否可以保证正确复制,即使它在技术上不是POD?什么时候绘制线条不何时可以对对象进行字节复制?
答案 0 :(得分:9)
是的,保证可以正确复制。
引用FDIS,§3.9/ 2:
对于普通可复制类型
T
的任何对象(基类子对象除外),无论对象是否包含类型T
的有效值,构成对象的基础字节可以复制到char
或unsigned char
的数组中。如果将char
或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-qualified 版本统称为 POD类型。 标量类型,简单的可复制类类型,此类类型的数组以及这些类型的cv限定版本统称为平易可复制类型 。
并且§9/ 6:
平易可复制的类是一个类:
- 没有非平凡的副本构造函数,
- 没有非平凡的移动构造函数,
- 没有非平凡的复制赋值运算符,
- 没有非平凡的移动赋值运算符,
- 有一个简单的析构函数。
答案 1 :(得分:5)
C ++ 11将POD类型的定义分解为更有用的类别,特别是“琐碎”和“标准布局”。您的示例是标准布局,并且是可复制的,尽管构造函数可以防止它完全无关紧要。保证平凡的可复制类型可以安全地按字节复制:
对于任何对象(基类子对象除外)的简单 可复制类型T,无论对象是否包含有效的类型值 T,构成对象的底层字节(1.7)可以复制到 char或unsigned char.40的数组如果是数组的内容 char或unsigned char被复制回对象,对象应该 随后保持其原始价值。
所以不,POD状态不需要以这种方式安全地复制,但是可以识别可能的非POD类型的子集。
答案 2 :(得分:3)
如果标准规定它仅为POD类型定义(我还没有详细检查C ++ 11标准,所以我不知道你的争论是否正确(a))并且您为非POD类型执行此操作,它不是已定义的行为。周期。
在一些实现中,在行星对齐时,在一天中的某些时间某些环境中,它可能起作用。它可能在绝大多数时间都有效。如果你重视可移植性,这仍然不是一个好主意。
(a)经过更多调查,看来你的具体情况还可以。标准的第3.9 / 3节(n3242 draft,但如果它从这个晚期草案中发生了很大变化,我会感到惊讶)说:
对于任何简单的可复制类型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
用于分配。