问题
I'm attempting to implement a tagged union.
My understanding was that in a C++ union, the non-trivial (i.e. not empty) destructors of non-static members are never called, thus we have to call them ourselves. That's what I did:
#include <iostream>
class C {
public:
C() {
std::cout << "C Ctor" << std::endl;
}
~C() {
std::cout << "C Dtor" << std::endl;
}
};
class B {
public:
B() {
std::cout << "B Ctor" << std::endl;
}
~B() {
std::cout << "B Dtor" << std::endl;
}
};
struct S {
int type;
union U {
C c;
B b;
U() {
}
~U() {}
} u;
S(int type) : type(type) {
if (type == 0) {
u.c = C();
} else {
u.b = B();
}
}
~S() {
if (type == 0) {
u.c.~C();
} else {
u.b.~B();
}
}
};
int main() {
S s(0);
return 0;
}
However, the output is:
C Ctor
C Dtor
C Dtor
Meaning, the C destructor is being called twice, instead of just once.
What is going on? And if you notice additional issues with my tagged union implementation, please point them out.
回答1:
In
S(int type) : type(type) {
if (type == 0) {
u.c = C();
} else {
u.b = B();
}
}
Since you are in the body of the constrcutor, u.c = C(); is not initialization but is instead assigment. That means you see the constructor called for C(), and then at the end of the expression the first destructor call is called to destroy that temporary. We can see this by adding
C& operator=(const C&) { std::cout << "operator=(const C&)\n"; return *this; }
to C which changes the output to
C Ctor
operator=(const C&)
C Dtor
C Dtor
Then the second destructor call is when s goes out of scope in main and its destructor is ran.
Do note that as is, the code has undefined behavior. Unions do not activate a member in the constructor user provided constructor you wrote so when you do
u.c = C();
you are assigning to an object that is not yet alive. You can't modify an object that isn't alive.
回答2:
In your constructor you create the temporary instance of C:
u.c = C();
which is copied and then destructed. So, first 2 lines of output belong to this instance. And the last output line is result of your ~S() call.
Besides this, beginning from C++17 you have standard powerful implementation of tagged union: https://en.cppreference.com/w/cpp/utility/variant
来源:https://stackoverflow.com/questions/62555368/destructor-of-union-member-seems-to-be-called-automatically