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.
unions never "remember" which field is active.
Your code outputs:
yes-c no-c no-d no-d yes-d
You seem to interpret the 3rd line (no-d) as a destructor call for a union field of your class, but that's not what happens here. ~u() isn't going to call destructors for y nor n.
You pass parameters to your constructors by value, thus this line is a destructor call for the parameter of the constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With