Undefined behavior of default constructor and destructor of anonymous union?
Asked Answered
S

0

6

The following code gives different compilation result with g++ 7.3 and clang++ 7.0, but to my knowledge all of copy constructor of S1, S2, S3 is deleted and none of the instantiation should success.

Question:

  1. Is such case (S1, S2) undefined in C++ standard?
  2. What is the difference between anonymous union without constructor/destructor implementation and named union with default constructor/destructor?
template <typename T>
struct S1
{
    union
    {
        T payload;
    };

    S1() {}
    ~S1() {}
};

template <typename T>
struct S2
{
    union
    {
        T payload;
    };

    S2() {}
    virtual ~S2() {}
};

template <typename T>
struct S3
{
    union U
    {
        T payload;

        U()  = default;
        ~U() = default;
    } storage;

    S3() {}
    ~S3() {}
};

#include <iostream>

struct A // overloaded A() & ~A()
{
    A()
    {
        std::cout << "A()" << std::endl;
    }
    ~A()
    {
        std::cout << "~A()" << std::endl;
    }
};

int main()
{
    {
        S1<A> a;
        auto  b = a; // g++ OK, clang++ OK
    }
    {
        S2<A> a;
        auto  b = a; // g++ fail, clang++ OK
    }
    {
        S3<A> a;
        auto  b = a; // g++ fail, clang++ fail
    }
    return 0;
}
Ship answered 15/11, 2019 at 6:37 Comment(4)
With both GCC and Clang, type traits show that S1<A> and S2<A> are both copy/move-constructible, while S3<A> is not. Weird.Sumerlin
Why would the copy constructors be deleted? A is trivially copyable/movable, so all the unions get a copy and a move constructor that are themselves trivial. (Also, what is the error? This isn’t about undefined behavior at runtime!)Workbag
@DavisHerring A is not trivially copyable/movable for the non-default ~A() implementation, but A is trivially copy/move assignableShip
@MidoriYakumo: Sorry, I was sloppy: A (and thence each union containing it) gets a trivial copy constructor (deprecatedly, despite the user-provided destructor) but is not trivially copyable. It gets no move constructor at all, but is still “movable” in that A(xvalue_A) works, so the union does get a defaulted, trivial move constructor.Workbag

© 2022 - 2024 — McMap. All rights reserved.