复制是否总是在C ++ 14中定义的可复制对象?

时间:2015-10-07 16:05:41

标签: c++ c++14 undefined-behavior

对于 trivially copyable 类型,请考虑:

void f(T z)
{
   T a;
   T b;
   std::memcpy(&b, &a, sizeof(T));

   a = z;
   b = z;

   // ...
}

此片段的行为是否在C ++ 14中定义

  1. T是char,
  2. T是int,或
  3. T是struct {int data; }; ?
  4. 假设f传递了一个包含有效值的对象。

    如果对memcpy的调用被副本分配 b = a取代,答案是否会更改?

    结果可以转移到复制构建 T(a)移动构建/作业吗?

    注意:与What are Aggregates and PODs and how/why are they special?相比,此问题特别关注复制不确定值的极端情况。

2 个答案:

答案 0 :(得分:4)

这里有几件事情可以发挥作用:

  • 评估为不确定值的表达式会导致未定义的行为,但有一些例外情况(8.5p12)
  • unsigned char(可能char,如果是无符号)是例外
  • 具有自动存储持续时间且其类型具有普通默认初始化的变量最初具有不确定的值(5.3.4p17)

这意味着

  • unsigned char没问题,无论是使用memcpy还是memmove还是使用copy-assignment或copy-constructor
  • memcpymemmove大概适用于所有类型,因为结果不是由评估产生的。 (为了满足此要求,实现可以在内部使用unsigned char,或利用针对其他类型的特定于实现的保证)
  • 如果右侧是不确定的值,其他类型的复制构造函数和复制赋值将失败

当然,即使是复制不确定值的有效方法也会创建另一个不确定的值。

段落编号对应于草案n4527

答案 1 :(得分:3)

是的,它适用于所有这些案例。如果将memcpy替换为复制分配(复制为简单的可复制类型逐字节复制。这就是使其变得微不足道的话),并且对于所有简单的可复制类型,移动不会改变答案建筑是复制建筑,所以也没有区别。

来自[basic.types]:

  

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

  

对于任何简单的可复制类型T,如果指向T的两个指针指向不同的T个对象obj1obj2,其中   如果复制构成obj1的基础字节(1.7),则obj2obj1都不是基类子对象   进入obj2obj2随后应与obj1保持相同的值。 [例如:

T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p contains
// the same value as the corresponding subobject in *t2p
     

-end example]

其中:

  

算术类型(3.9.1),枚举类型,指针类型,指向成员类型的指针(3.9.2),std :: nullptr_-   t和这些类型的cv限定版本(3.9.3)统称为标量类型。标量类型,POD类   (第9条),这些类型的数组和这些类型的cv限定版本(3.9.3)统称为POD   类型。 Cv不合格的标量类型,平凡的可复制类类型(第9条),此类类型的数组和非易失性   这些类型的const限定版本(3.9.3)统称为平凡可复制类型

来自[class]的地方:

  

平易可复制的课程是一个类:   (6.1) - 没有非平凡的复制构造函数(12.8),
  (6.2) - 没有非平凡的移动构造函数(12.8),
  (6.3) - 没有非平凡的文件分配操作员(13.5.3,12.8),
  (6.4) - 没有非平凡的移动指派算子(13.5.3,12.8)和
  (6.5) - 有一个简单的析构函数(12.4)。

因此,charintstruct { int data; };都是可复制的类型。前两个是cv不合格的标量类型,后者是一个简单的可复制类类型。