Working with a union
of two classes, it appears in this simple example that the union
remembers the last class stored in it and calls the correct destructor for that object:
#include <iostream>
using std::cout;
using std::endl;
struct yes{
yes(){cout<<"yes-c"<<endl;}
~yes(){cout<<"yes-d"<<endl;}
};
struct no{
no(){cout<<"no-c"<<endl;}
~no(){cout<<"no-d"<<endl;}
};
struct u{
union{
yes y;
no n;
};
u(yes _y):y(_y){}
u(no _n):n(_n){}
~u(){}
};
int main() {
yes y;
no n;
{
u uu(n);
}
return 0;
}
Output:
yes-c
no-c
no-d
no-d
yes-d
So the uu
will call the correct destructor ~no()
for the union, as if it records the type when the union is constructed. How does this work?
Short answer: It doesn't.
If you add a copy-constructor to no
you will see that there are actually three no
objects being created, but only two are destructed.
First you create the object n
. Then when you pass it by value to the u
constructor, it is copied once into the _n
argument. That _n
object is then copied into the uu.n
member.
The destructions are of the _n
argument in the u
constructor, and the n
object in the main
function.
Here's your program with some slight modification to add the copy-constructor and to keep track of the no
objects:
#include <iostream>
struct yes{
yes(){std::cout<<"yes-c"<<std::endl;}
~yes(){std::cout<<"yes-d"<<std::endl;}
};
struct no{
no(){std::cout<<"no-c : "<<n<<std::endl;}
no(no const& o)
: n(o.n + 1)
{
std::cout << "no-cc : " << o.n << " -> " << n << '\n';
}
~no(){std::cout<<"no-d : "<<n<<std::endl;}
int n = 0;
};
struct u{
union{
yes y;
no n;
};
u(yes _y):y(_y){}
u(no _n):n(_n){}
~u(){}
};
int main()
{
yes y;
no n;
{
u uu(n);
}
}
Without optimizations or copy-elision this will create the output
yes-c no-c : 0 no-cc : 0 -> 1 no-cc : 1 -> 2 no-d : 1 no-d : 0 yes-d
The output no-c : 0
is for the creation of the n
object in the main
function.
The output no-cc : 0 -> 1
is for the copying into the u
constructor argument _n
.
The output no-cc : 1 -> 2
is for the copying of the argument _n
into the unions n
object.
The output no-d : 1
is the destruction of the _n
argument.
The output no-d : 0
is the destruction of the n
object in the main
function.