Title
Trivial copyability and unions with non-trivial members
Status
open
Section
11.2 [class.prop]
Submitter
Daveed Vandevoorde

Created on 2020-11-30.00:00:00 last changed 13 months ago

Messages

Date: 2023-03-15.00:00:00

Additional notes (March, 2023)

std::tuple with trivially-copyable element types and with no elements (std::tuple<>) ought to be trivially copyable, but the recent addition of const-qualified assignment operators makes that not so under the status quo core language rules.

Date: 2023-03-11.14:38:32

CWG 2022-11-10

Traditionally, the rule for trivial copyability has been that each of the potentially user-written ways of copying a class (copy/move constructors, copy/move assignment operators) have to be trivial (or deleted). See C++17 subclause 12p6:

A trivially copyable class is a class:
  • where each copy constructor, move constructor, copy assignment operator, and move assignment operator (15.8, 16.5.3) is either deleted or trivial,
  • that has at least one non-deleted copy constructor, move constructor, copy assignment operator, or move assignment operator, and
  • that has a trivial, non-deleted destructor (15.4).

That seems unhelpful. The rule should instead be that if there is any way of copying the class such that the compiler will generate a memcpy (because the corresponding operation is trivial), the user should be allowed to perform memcpy, too. In terms of wording, this amounts to striking the first bullet and adding "trivial" to the second bullet. (The wording in the current working draft considers eligibility, which complicates the treatment slightly in terms unrelated to the present issue.)

CWG is seeking EWG advice on this issue via cplusplus/papers#1363.

Date: 2022-11-11.15:29:08

According to 11.2 [class.prop] paragraph 1,

A trivially copyable class is a class:

  • that has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator (11.4.4 [special], 11.4.5.3 [class.copy.ctor], 11.4.6 [class.copy.assign]),

  • where each eligible copy constructor, move constructor, copy assignment operator, and move assignment operator is trivial, and

  • that has a trivial, non-deleted destructor (11.4.7 [class.dtor]).

This definition has surprising effects in a union whose members are not trivial. For example:

  struct S {
    S& operator=(const S&);
  };
  union U {
    S s;
  };

In this case, S is not trivially copyable because its assignment operator is non-trivial, although its copy constructor is trivial. U, however, is trivially copyable because its assignment operator is not eligible (11.4.4 [special] paragraph 6) because it is deleted, but its copy constructor is trivial, thus satisfying the second bullet.

It is unclear why, for example, a complete object of type S cannot be memcpyed but such an object can be memcpyed when embedded in a union.

There is implementation divergence in the handling of this example.

History
Date User Action Args
2023-03-11 14:38:32adminsetmessages: + msg7220
2022-11-11 15:29:08adminsetmessages: + msg7020
2020-11-30 00:00:00admincreate