Given a union:
#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>
#include <cassert>
#include <cstdlib>
struct A { int a; };
struct B { int b; };
template< typename X >
struct S
{
std::size_t tag;
std::unique_ptr< X > x;
};
union U
{
S< A > a;
S< B > b;
U(A x) : a{0, std::make_unique< A >(x)} { ; }
U(B x) : b{1, std::make_unique< B >(x)} { ; }
std::size_t tag() { return a.tag; }
~U()
{
switch (tag()) {
case 0 : {
a.~S< A >();
break;
}
case 1 : {
b.~S< B >();
break;
}
default : assert(false);
}
}
void
swap(U & u) noexcept
{
a.x.swap(u.a.x);
std::swap(a.tag, u.a.tag);
}
};
static_assert(std::is_standard_layout< U >{});
int
main()
{
U a{A{ 0}};
U b{B{~0}};
assert((a.tag() == 0) && (a.a.x->a == 0));
assert((b.tag() == 1) && (b.b.x->b == ~0));
a.swap(b);
assert((a.tag() == 1) && (a.b.x->b == ~0));
assert((b.tag() == 0) && (b.a.x->a == 0));
return EXIT_SUCCESS;
}
U::tag()
funcion is correct due to it permittable to inspect common initial subsequence of alternative data members in U
-like unions.
U::swap()
works, but is it legal for std::unique_ptr
s? Is it allowed to swap non-active std::unique_ptr
s alternative data members of U
-like unions?
It seems to be permittable due to simple nature of std::unique_ptr< X >
: it is just a wrapper over X *
and for any A
and B
I sure static_assert((sizeof(A *) == sizeof(B *)) && (alignof(A *) == alignof(B *)));
holds and pointers arrangement is identical for all types (except pointers to data members and member functions of classes). Is it true?
Example code works fine. But very likely there is UB if we read the standard.