Shea Levy
Shea Levy

Reputation: 5435

Is it legal to activate nested unions via the address of their members?

Is the following code legal (in c++11/14)?

bool foo() {
  union bar { int i; bool b; };
  union baz { char c; bar b; };
  auto b = baz{'x'};
  auto barptr = &b.b;
  auto boolptr = &barptr->b;
  new (boolptr) bool{true};
  return b.b.b;
}

This example is silly, but I'm playing around with a variadic variant implementation that uses nested unions instead of a char [] block for the variant members, and allowing this will make my current attempt at the copy constructor cleaner.

To break it down into two subquestions:

  1. Is the assignment of boolptr by accessing a member of barptr legal even though b.b is inactive?
  2. Does the in-place construction of boolptr activate b.b and b.b.b?

References to the standard would be appreciated.

Upvotes: 7

Views: 119

Answers (1)

Casey
Casey

Reputation: 42584

As with so many questions about unions and type-punning, it's unclear if your program has defined behavior although I strongly expect it to behave as expected in any sane implementation. What I can say with certitude is that this program:

#include <memory>
#include <new>

template <typename T>
inline void destruct(T& t) { t.~T(); }

template <typename T, typename...Args>
inline void construct(T& t, Args&&...args) {
  ::new((void*)std::addressof(t)) T(std::forward<Args>(args)...);
}

template <typename T>
inline void default_construct(T& t) {
  ::new((void*)std::addressof(t)) T;
}

bool foo() {
  union bar { int i; bool b; };
  union baz { char c; bar b; };
  auto b = baz{'x'};
  destruct(b.c);
  default_construct(b.b);
  construct(b.b.b, true);
  return b.b.b;
}

is standard-compliant, has exactly the effects you desire, and compiles to exactly the same assembly as the original program in modern compilers. Original:

foo():
    movl    $1, %eax
    ret

Guaranteed-compliant:

foo():
    movl    $1, %eax
    ret

Upvotes: 2

Related Questions