It is legal to use active and non-active members of a union if they are standard layout types e.g. like primitive types as int
.
On the other hand it is UB to const_cast
-away the volatile
of a simple variable and use that variable.
Is it legal (no UB) to use both members of this union?
union VU {
int nv;
volatile int v;
};
More formal this should be
union VU {
struct {
int v;
} nv;
struct {
volatile int v;
} v;
};
If by "use both members of this union" you mean attempting to exploit the common initial sequence rules to access a volatile
object through a non-volatile
glvalue:
union VU {
struct {
int v;
} nv;
struct {
volatile int v;
} v;
};
VU x;
x.v.v = 42;
std::cout << x.nv.v;
the answer is no, it's not legal. [class.mem.general]/26 is actually very clear about this:
In a standard-layout union with an active member of struct type
T1
, it is permitted to read a non-static data memberm
of another union member of struct typeT2
providedm
is part of the common initial sequence ofT1
andT2
; the behavior is as if the corresponding member ofT1
were nominated. [Example 5: ... ] [Note 10: Reading a volatile object through a glvalue of non-volatile type has undefined behavior ([dcl.type.cv]). — end note]
In the above example, the behaviour of reading x.nv.v
is as if the corresponding member of the actually active member were nominated, i.e., it reads the member x.v.v
of the active member x.v
. Since this is a read of the volatile object x.v.v.
through a non-volatile glvalue, the behavior is undefined.
On the other hand if you were to do it the other way around (make x.nv.v
active, then read it through x.v.v
) then it would be legal; it wouldn't be any different from reading through const_cast<volatile int&>(x.nv.v)
.