Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ "Choice" Union

Tags:

c++

unions

choice

Not sure if there is a term for this, "choice" seems to work. I'm working in C++, and I have a bunch of unions I need to create where the union represents a choice of one of the members of the union. The current "choice" is tracked and is always available. I am currently coding these "unions" manually, but I'm wondering whether there is any neat trick for doing this sort of thing (semi-)automatically.

I ran into the union limitation of not having assignment operator overloads or non-trival constructors or copy constructors on my first bout of trying to implement this, but realized that because I'm actually tracking the current "choice", there is very defined behavior to take under almost every situation.

Here is what I'm doing right now, (for only two choices, could be up to 10 or 15) and it's quite a significant amount of code nearly all of which is just boilerplate. Also, if anyone has any comments on whether or not what I have below is even valid that would be awesome, still picking up some of the craziness of C++...

struct MyChoice
{
    struct Choice1
    {
        int a;
        char* b;
    };

    struct Choice2
    {
        bool c;
        double d;
    };

    enum Choice
    {
        Choice_Choice1,
        Choice_Choice2
    } choice;

    char _value[max(sizeof(Choice1),sizeof(Choice2))]; // could be private
    Choice1& choice1()
    {
        if(choice == Choice_Choice2)
        {
            (*(Choice2*)_value)->~Choice2();
            (*(Choice1*)_value) = Choice1();
            choice = Choice_Choice1;
        }
        return *(Choice1*)_value;
    }
    Choice2& choice2()
    {
        if(choice == Choice_Choice1)
        {
             (*(Choice1*)_value)->~Choice1();
             (*(Choice2*)_value) = Choice2();
             choice = Choice_Choice2; 
        }
        return *(Choice2*)_value;
    }
    MyChoice()
    {
       _choice = Choice_Choice1;
       (*(Choice1)_value) = Choice1();
    }
    MyChoice(const MyChoice& other)
    {
       this->_choice = other.choice;
       if(this->_choice == Choice_Choice1)
          (*(Choice1*)_value) = other.choice1();
       else
          (*(Choice2*)_value) = other.choice2();
    }
    ~MyChoice()
    {
        if(_choice == Choice_Choice1)
            (*(Choice1)_value)->~Choice1();
        else
            (*(Choice2)_value)->~Choice2();
    }
};

Thanks for your help SO

like image 890
LorenVS Avatar asked Jul 21 '10 21:07

LorenVS


People also ask

When union is used in C?

A union is a special data type available in C that allows to store different data types in the same memory location. You can define a union with many members, but only one member can contain a value at any given time. Unions provide an efficient way of using the same memory location for multiple-purpose.

Why is union preferred over structure?

Union is preferred over struct when only one of the member elements of the union is stored.

In which scenario union is better than structure?

Union takes less memory space as compared to the structure. Only the largest size data member can be directly accessed while using a union. It is used when you want to use less (same) memory for different data members.


1 Answers

Try looking at boost::any and boost::variant. The first one enables you to insert any type in a boost::any variable, tracking its type. It's more a "check-at-runtime" type. The second one force you to define all the types to be inserted (ie boost::variant < Choice1, Choice2, ... > ), but enforce more type-checking at compile time.

Both are used to store object of different types, for example to have heterogeneous containes (std::vector can handle std::string or int for example).

like image 116
Scharron Avatar answered Sep 21 '22 14:09

Scharron