Reputation: 23
I have got a union of two members.
union myUnion {
std::wstring mem1;
int mem2;
myUnion(std::wstring in){
this->mem1 = in;
}
myUnion(int in){
this->mem2 = in;
}
myUnion(const myUnion& in){
if(this->mem2){
this->mem2 = in.mem2;
}else{
this->mem1 = in.mem1;
}
}
};
//and then I make a vector out of the union:
std::vector<myUnion> unions;
//but when I try to push_back:
unions.push_back(L"A");
it soon breaks out a run time error: 0xC0000005: Access violation writing location 0xCCCCCCCC. and when I try to debug this program, I realize that mem1 have not been allocate a memory. I really don't know why this happens and I want to know how can i fix it.
Upvotes: 2
Views: 156
Reputation: 106096
Your copy constructor is broken as...
if(this->mem2){
...will return true for any mem2
value other than 0
, and if the union was actually constructed with a string then mem2
is the first sizeof mem2
bytes from mem1
: quite likely to be non-0. If you want a union-like object to copy itself properly, you generally need to wrap it in an outer struct
that adds some integral/enum type to keep track of the union's current datatype. Other behaviours including your myUnion(wstring)
constructor and destructor are also flawed.
Handling unions without invoking undefined behaviour is tricky - you're best off using boost::variant
instead.
Upvotes: 1
Reputation: 16204
In C++, union
is not a very natural datatype, because it doesn't really fit naturally with the whole C++ idea of constructors and destructors. When you create a union in C++, it does not call constructors for any of its possible types, because they would all be writing on top of eachother.
So this constructor
myUnion(std::wstring in){
this->mem1 = in;
}
will crash because this->mem1
's lifetime as a string has not been started. You would have to use something like, call std::string
ctor using placement new at that address. Later, if you change the data type, you will have to make sure to remember to call the dtor for this->mem1
also before you start writing to a different field of the union, or you will get memory leakage or corruption.
By far the simpler way to do what you are trying to do in C++ is to use a variant type like boost::variant
which is going to handle all the boilerplate and all the details for you. (Union is okay if you are only using trivial types with no ctors or dtors.)
typedef boost::variant<std::wstring, int> MyUnion;
std::vector<MyUnion> unions;
unions.push_back(L"A");
Upvotes: 3