复制平凡可复制的对象是否总是在 C++14 中定义?
Is copying trivially copyable objects always defined in C++14?
对于trivially copyable类型T考虑:
void f(T z)
{
T a;
T b;
std::memcpy(&b, &a, sizeof(T));
a = z;
b = z;
// ...
}
这个片段的行为是在C++14中定义的 if
- T 是字符,
- T 是整数,或者
- T是struct { int data; }; ?
假设 f
传递了一个包含有效值的对象。
如果对 memcpy
的调用被 复制赋值 替换,答案会改变吗?b = a
?
结果能否转入copy construction T(a)
and move construction/assignment?
注意:与What are Aggregates and PODs and how/why are they special?相比,这个问题特别关注复制不确定值的极端情况.
是的,它对所有这些情况都有明确的定义。如果 memcpy
被复制赋值替换(复制平凡可复制类型 是 字节复制。这就是它平凡的原因),并且对于所有平凡可复制类型,移动构造是复制构造,所以也没有区别。
来自[basic.types]:
For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object
holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array
of char or unsigned char. If the content of the array of char or unsigned char is copied back into the
object, the object shall subsequently hold its original value.
和:
For any trivially copyable type T
, if two pointers to T
point to distinct T
objects obj1
and obj2
, where
neither obj1
nor obj2
is a base-class subobject, if the underlying bytes (1.7) making up obj1
are copied
into obj2
, obj2
shall subsequently hold the same value as obj1
. [ Example:
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 ]
其中:
Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_-
t, and cv-qualified versions of these types (3.9.3) are collectively called scalar types. Scalar types, POD classes
(Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD
types. Cv-unqualified scalar types, trivially copyable class types (Clause 9), arrays of such types, and nonvolatile
const-qualified versions of these types (3.9.3) are collectively called trivially copyable types.
哪里,来自[class]:
A trivially copyable class is a class that:
(6.1) — has no non-trivial copy constructors (12.8),
(6.2) — has no non-trivial move constructors (12.8),
(6.3) — has no non-trivial copy assignment operators (13.5.3, 12.8),
(6.4) — has no non-trivial move assignment operators (13.5.3, 12.8), and
(6.5) — has a trivial destructor (12.4).
因此,char
、int
和 struct { int data; };
都是普通可复制类型。前两个是 cv-unqualified 标量类型,后者是可平凡复制的 class 类型。
这里有几件事在起作用:
- 计算为不确定值的表达式会导致未定义的行为,但有某些例外 (8.5p12)
unsigned char
(如果未签名,可能 char
)是例外情况
- 具有自动存储持续时间且其类型具有简单默认初始化的变量最初具有不确定的值 (5.3.4p17)
这意味着
unsigned char
没问题,无论是使用 memcpy
或 memmove
还是复制赋值或复制构造函数
memcpy
和 memmove
大概适用于所有类型,因为结果不是 "produced by an evaluation"(为了满足这个要求,实现可以在内部使用 unsigned char
,或利用针对其他类型的特定于实现的保证)
- 如果右侧是不确定值,其他类型的复制构造函数和复制赋值将失败
当然,即使复制不确定值的有效方法也会创建另一个不确定值。
段落编号对应于草案 n4527
对于trivially copyable类型T考虑:
void f(T z)
{
T a;
T b;
std::memcpy(&b, &a, sizeof(T));
a = z;
b = z;
// ...
}
这个片段的行为是在C++14中定义的 if
- T 是字符,
- T 是整数,或者
- T是struct { int data; }; ?
假设 f
传递了一个包含有效值的对象。
如果对 memcpy
的调用被 复制赋值 替换,答案会改变吗?b = a
?
结果能否转入copy construction T(a)
and move construction/assignment?
注意:与What are Aggregates and PODs and how/why are they special?相比,这个问题特别关注复制不确定值的极端情况.
是的,它对所有这些情况都有明确的定义。如果 memcpy
被复制赋值替换(复制平凡可复制类型 是 字节复制。这就是它平凡的原因),并且对于所有平凡可复制类型,移动构造是复制构造,所以也没有区别。
来自[basic.types]:
For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char. If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value.
和:
For any trivially copyable type
T
, if two pointers toT
point to distinctT
objectsobj1
andobj2
, where neitherobj1
norobj2
is a base-class subobject, if the underlying bytes (1.7) making upobj1
are copied intoobj2
,obj2
shall subsequently hold the same value asobj1
. [ Example: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 ]
其中:
Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_- t, and cv-qualified versions of these types (3.9.3) are collectively called scalar types. Scalar types, POD classes (Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD types. Cv-unqualified scalar types, trivially copyable class types (Clause 9), arrays of such types, and nonvolatile const-qualified versions of these types (3.9.3) are collectively called trivially copyable types.
哪里,来自[class]:
A trivially copyable class is a class that:
(6.1) — has no non-trivial copy constructors (12.8),
(6.2) — has no non-trivial move constructors (12.8),
(6.3) — has no non-trivial copy assignment operators (13.5.3, 12.8),
(6.4) — has no non-trivial move assignment operators (13.5.3, 12.8), and
(6.5) — has a trivial destructor (12.4).
因此,char
、int
和 struct { int data; };
都是普通可复制类型。前两个是 cv-unqualified 标量类型,后者是可平凡复制的 class 类型。
这里有几件事在起作用:
- 计算为不确定值的表达式会导致未定义的行为,但有某些例外 (8.5p12)
unsigned char
(如果未签名,可能char
)是例外情况- 具有自动存储持续时间且其类型具有简单默认初始化的变量最初具有不确定的值 (5.3.4p17)
这意味着
unsigned char
没问题,无论是使用memcpy
或memmove
还是复制赋值或复制构造函数memcpy
和memmove
大概适用于所有类型,因为结果不是 "produced by an evaluation"(为了满足这个要求,实现可以在内部使用unsigned char
,或利用针对其他类型的特定于实现的保证)- 如果右侧是不确定值,其他类型的复制构造函数和复制赋值将失败
当然,即使复制不确定值的有效方法也会创建另一个不确定值。
段落编号对应于草案 n4527