hmcll
hmcll

Reputation: 23

how can i allocate memory for a union member that haven't been initialized

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

Answers (2)

Tony Delroy
Tony Delroy

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

Chris Beck
Chris Beck

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

Related Questions