C ++ 11中类型的字节转换副本?

时间:2011-09-24 00:32:48

标签: c++ c++11 language-lawyer standard-layout

C ++ 11标准保证逐字节副本始终对POD类型有效。但是某些琐碎的类型呢?

以下是一个例子:

struct trivial
{
  int x;
  int y;
  trivial(int i) : x(2 * i) { std::cout << "Constructed." << std::endl; }
};

如果我要逐字节地复制这个结构,它是否可以保证正确复制,即使它在技术上不是POD?什么时候绘制线条何时可以对对象进行字节复制?

3 个答案:

答案 0 :(得分:9)

是的,保证可以正确复制。

引用FDIS,§3.9/ 2:

  

对于普通可复制类型 T的任何对象(基类子对象除外),无论对象是否包含类型T的有效值,构成对象的基础字节可以复制到charunsigned char的数组中。如果将charunsigned char数组的内容复制回对象,则该对象应随后保持其原始值。

并且§3.9/ 3:

  

对于任何平凡的可复制类型 T,如果指向T的两个指针指向不同的T个对象obj1obj2obj1obj2都不是基类子对象,如果构成obj1的基础字节被复制到obj2obj2随后将保留与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用于分配。