Unions in C++?

Aug 9, 2013 at 9:20am
im very fail to understand why unions are good for
Aug 9, 2013 at 9:28am
Ive nevery used unions or come across unions in codes, the whole concept of shared memory in unions is really dangerous, it can cause corruption of memory if not used properly, unions were used in old times when memory was really really expensive!!!!
Aug 9, 2013 at 9:43am
Say you are going to need an int or you are going to need a double (but never both at the same time) depending on some other variables. Instead of wasting memory for both an int and a double you can use a union that will only take up as much memory that is needed to store the largest of the two types.
Aug 9, 2013 at 9:47am
closed account (z05DSL3A)
anirudh sn wrote:
Ive nevery used unions or come across unions in codes, the whole concept of shared memory in unions is really dangerous, it can cause corruption of memory if not used properly, unions were used in old times when memory was really really expensive!!!!

An example of union in real life code, SDL_Event [General event structure]
http://hg.libsdl.org/SDL/file/b4b0e9f1669c/include/SDL_events.h#l420

The benefits: A single data type to handle all the event types without wasting memory unnecessarily.


Aug 9, 2013 at 9:52am
we use VARIANTs at work for populating our datagrids. these are unions under the hood. like peter said it means i dont have to worry about methods with different arguments to pass in depending on variable type. i just pass in a variant type.
Aug 9, 2013 at 9:56am
@GreyWolf, apart from critical memory intensive applications wherein the memory is really scarse, does it make sense to use unions anywhere?? especially in normally application programming, arent there high chances of memory corruption if used wrongly??
Aug 9, 2013 at 10:02am
apart from critical memory intensive applications wherein the memory is really scarse, does it make sense to use unions anywhere??

Did you follow the link in his post? SFML also uses something similar for event handling.


especially in normally application programming, arent there high chances of memory corruption if used wrongly??

That can be said of most C++ constructs. It's quite easy to shoot yourself in the foot.
Aug 9, 2013 at 10:22am
It may be relevant for interpreting the data contained in a file. For example a JPEG image from a digital camera contains EXIF information, detailing the camera settings used etc. Or image files such as RAW or TIFF, when you start to decode them, a union may be used to represent a portion of data which needs to be interpreted in one of several different ways.
Aug 9, 2013 at 10:32am
closed account (z05DSL3A)
anirudh sn wrote:
apart from critical memory intensive applications wherein the memory is really scarse, does it make sense to use unions anywhere??
Its use is more about being efficient and efficiency bring benefits in all sorts of areas. Do you really want a data type where 90% of it is always junk, or 10 data types to handle instead of one?
Aug 9, 2013 at 1:28pm
It was useful for providing a kind of crude subclassing of structs in C code. I've seen code that did something like:

1
2
3
4
5
6
7
8
9
10
struct BaseType
{
  int type;
  float baseData;
  union
  {
    struct SpecialisedTypeAData;
    struct SpecialisedTypeBData;
  }
};


So baseData corresponds to "base class" data, i.e. data that was common to all of the specialised types, and the union holds the "derived class" data - i.e. data relating only to one particular specialised type.

I've only ever seen this in C code, or code that was copied and pasted from C into C++ without properly refactoring it.
Aug 9, 2013 at 1:30pm
Its use is more about being efficient and efficiency bring benefits in all sorts of areas. Do you really want a data type where 90% of it is always junk, or 10 data types to handle instead of one?

Unless I was working in an environment where memory was very limited, I would want a data type that is clearly understandable and maintainable, with as little chance for confusion or introduction of errors as possible.

I wouldn't compromise that for the sake of using less memory, unless it was absolutely necessary.
Aug 9, 2013 at 3:15pm
> apart from critical memory intensive applications wherein the memory is really scarse,
> does it make sense to use unions anywhere??

I idea of a union exists primarily because the language is statically typed, are there are situations where we need to deal with a truly heterogeneous set of types. It is rarely used for scrounging memory.


> especially in normally application
> programming, arent there high chances of memory corruption if used wrongly??

In well-written C++ code, we almost always find that the unions used are type-safe discriminated unions - what the IS refers to as a 'union like class'.

This is the general idea:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>
#include <string>
#include <new>
#include <memory>

struct int_or_str
{
    bool is_int() const { return is_int_ ; }
    bool is_str() const { return !is_int() ; }

    ~int_or_str() { if( is_str() ) str.std::string::~string() ; }

    int_or_str( int v = 0 ) : i(v) {}
    int_or_str( const std::string& s ) : is_int_(false) { ::new ( std::addressof(str) ) std::string(s) ; }
    int_or_str( std::string&& s ) : is_int_(false) { ::new ( std::addressof(str) ) std::string( std::move(s) ) ; }
    int_or_str( const char* cstr ) : is_int_(false) { ::new ( std::addressof(str) ) std::string(cstr) ; }

    int_or_str( const int_or_str& that ) : is_int_( that.is_int_)
    {
        if( that.is_int() ) i = that.i ;
        else ::new ( std::addressof(str) ) std::string( that.str ) ;
    }

    int_or_str( int_or_str&& that ) : is_int_( that.is_int_)
    {
        if( that.is_int() ) i = that.i ;
        else ::new ( std::addressof(str) ) std::string( std::move(that.str) ) ;
    }

    int_or_str& operator= ( const int_or_str& that )
    {
        if( this != std::addressof(that) )
        {
            if( is_str() && that.is_str() ) str = that.str ;
            else
            {
                if( is_str() ) str.std::string::~string() ;
                is_int_ = that.is_int() ;
                if( is_int() ) i = that.i ;
                else ::new ( std::addressof(str) ) std::string( that.str ) ;
            }
        }
        return *this ;
    }

    int_or_str& operator= ( int_or_str&& that )
    {
        if( this != std::addressof(that) )
        {
            if( is_str() && that.is_str() ) str = std::move(that.str) ;
            else
            {
                if( is_str() ) str.std::string::~string() ;
                is_int_ = that.is_int() ;
                if( is_int() ) i = that.i ;
                else ::new ( std::addressof(str) ) std::string( std::move(that.str) ) ;
            }
        }
        return *this ;
    }

    /*explicit*/ operator int() const { if( !is_int() ) throw "whatever" ; return i ; }
    /*explicit*/ operator int&() { if( !is_int() ) throw "whatever" ; return i ; }
    /*explicit*/ operator const std::string&() const { if( is_int() ) throw "whatever" ; return str ; }
    /*explicit*/ operator std::string&() { if( is_int() ) throw "whatever" ; return str ; }

    private:

        bool is_int_ = true ; // discriminant

        union // anonymous union
        {
            std::string str ;
            int i ;
        };
};

std::ostream& operator<< ( std::ostream& stm, const int_or_str& v )
{
    if( v.is_int() ) return stm << int(v) ;
    else return stm << std::string(v) ;
}


We can use the union like class it in a completely type safe manner. In practice, we would just use a library; for instance boost::any or boost::variant

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main()
{
    {
        int_or_str v = "hello" ;
        std::cout << v << ' ' ;
        std::string str = v ;
        v = 123 ;
        std::cout << v << ' ' ;
        v = str ;
        std::cout << v << '\n' ;
    }

    {
        // in practice, we use a library
        // #include <boost/variant.hpp>
        boost::variant< std::string, int > v = "hello" ;
        std::cout << v << ' ' ;
        std::string str = boost::get<std::string>(v) ;
        v = 123 ;
        std::cout << v << ' ' ;
        v = str ;
        std::cout << v << '\n' ;
    }
}
Topic archived. No new replies allowed.