Is copying trivially copyable objects always defin

2019-02-25 14:48发布

For a trivially copyable type T consider:

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

   a = z;
   b = z;

   // ...
}

Is the behavior of this fragment defined in C++14 if

  1. T is char,
  2. T is int, or
  3. T is struct { int data; }; ?

Assume that f gets passed an object that holds a valid value.

Do the answers change if the call to memcpy is replaced by copy assignment b = a?

Can the results be carried over to copy construction T(a) and move construction/assignment?


Note: This question, in contrast to What are Aggregates and PODs and how/why are they special?, is particularly concerned with the corner case of copying indeterminate values.

2条回答
The star\"
2楼-- · 2019-02-25 14:53

There are a couple things at play here:

  • an expression evaluating to an indeterminate value causes undefined behavior, with certain exceptions (8.5p12)
  • unsigned char (and possibly char, if unsigned) is the exception
  • variables with automatic storage duration and whose types have trivial default initialization initially have indeterminate values (5.3.4p17)

This means that

  • unsigned char is fine, no matter whether using memcpy or memmove or copy-assignment or copy-constructor
  • memcpy and memmove is presumably fine for all types, because the result is not "produced by an evaluation" (to meet this requirement, an implementation can use unsigned char internally, or take advantage of implementation-specific guarantees made for other types)
  • copy-constructor and copy-assignment for other types will fail if the right-hand-side is an indeterminate value

Of course, even the valid methods for copying an indeterminate value create another indeterminate value.


Paragraph numbers correspond to draft n4527

查看更多
虎瘦雄心在
3楼-- · 2019-02-25 15:12

Yes, it's well defined for all those cases. The answers do not change if memcpy is replaced by copy assignment (copying for trivially copyable types is byte-wise copy. That's what makes it trivial), and for all trivially copyable types, move construction IS copy construction, so there's no difference there either.

From [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.

and:

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 ]

where:

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.

Where, from [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).

So, char, int, and struct { int data; }; are all trivially copyable types. The former two are cv-unqualified scalar types and the latter is a trivially copyable class type.

查看更多
登录 后发表回答