13

What makes a union member active?

I've read chapter 9.5 of the C++14 standard (the one about unions), but I haven't found a clear answer to what makes a union member active.

There is a note:

In general, one must use explicit destructor calls and placement new operators to change the active member of a union.

So for example,

union U {
  int i;
  short s;
} u;

new(&u.i) int(42);

Okay, placement new changes the active member, it's clear. But we usually don't use placement new when working with types with trivial constructors.

Does operator= change the active member without UB?

u.i = 42;

Here, operator= called on an unconstructed object. Is it well defined?

What about this?

struct A {
  int i0;
  int i1;
};
union U {
  A a;
  short s;
} u;

What makes a to be the active member of u? Is setting both i0 & i1 enough?

u.a.i0 = 42;
u.a.i1 = 99;

What if I write:

u.a.i0 = 42;     // supposedly this doesn't change the active member to a, as i1 isn't set
int x = u.a.i0;  // is it fine to read from a.i0? a is not an active member supposedly

After u.a.i0 = 42;, the active member isn't changed to a (I think), so is it UB to do int x = u.a.i0;?

Does C++17 improve on the description of active members?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
geza
  • 28,403
  • 6
  • 61
  • 135
  • "Here, `operator=` called on an unconstructed object" are you sure? It's POD so it seems fine. – BartoszKP Nov 07 '17 at 22:24
  • 1
    Laymen definition is that this is the element last written to. But I can't find any substantiation of this in the standard. – SergeyA Nov 07 '17 at 22:24
  • @BartoszKP: well, it's DynamicType is certainly (?) not `int`, so... I don't know :) – geza Nov 07 '17 at 22:27
  • 3
    This is fixed in C++17, which describes the process of switching an active member in greater detail in [**\[class.union\]/5**](http://eel.is/c++draft/class.union#5) – Igor Tandetnik Nov 07 '17 at 22:30
  • 1
    @IgorTandetnik, your comment is actually an answer. – SergeyA Nov 07 '17 at 22:32
  • 1
    @SergeyA Well, the question is specifically about C++14. I don't have an answer for that. – Igor Tandetnik Nov 07 '17 at 22:33
  • @IgorTandetnik: whoops. I didn't expect that they improved on this (usually they focus on high level stuff). I edited my answer, so a C++17 related answer is absolutely OK for me. But even I can now answer my question :) – geza Nov 07 '17 at 22:36
  • 1
    @IgorTandetnik this was reworded with [P0137R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0137r1.html) which resolves [DR1116](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1116) which has `CD4` status which I believe means the defect applies to C++14 as well but not 100% on that. – Shafik Yaghmour Nov 07 '17 at 22:45

1 Answers1

9

In C++17, a paragraph was added that explicitly discusses cases like u.i = 42:

[class.union]/5 When the left operand of an assignment operator involves a member access expression (8.2.5) that nominates a union member, it may begin the lifetime of that union member, as described below. For an expression E, define the set S(E) of subexpressions of E as follows:

(5.1) — If E is of the form A.B, S(E) contains the elements of S(A), and also contains A.B if B names a union member of a non-class, non-array type, or of a class type with a trivial default constructor that is not deleted, or an array of such types.

(5.2) — If E is of the form A[B] and is interpreted as a built-in array subscripting operator, S(E) is S(A) if A is of array type, S(B) if B is of array type, and empty otherwise.

(5.3) — Otherwise, S(E) is empty.

In an assignment expression of the form E1 = E2 that uses either the built-in assignment operator (8.18) or a trivial assignment operator (15.8), for each element X of S(E1), if modification of X would have undefined behavior under 6.8, an object of the type of X is implicitly created in the nominated storage; no initialization is performed and the beginning of its lifetime is sequenced after the value computation of the left and right operands and before the assignment. [ Note: This ends the lifetime of the previously-active member of the union, if any (6.8). —end note ]

(Followed by a longish example that I'm too lazy to format properly, but which you can see here.)

Language Lawyer
  • 3,378
  • 1
  • 12
  • 29
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85