VS 2013 exception when using C++11 unrestricted unions

175 views Asked by At

Consider this code:

struct TNumeric {
    bool    Negative;
    wstring Integral;
    wstring Fraction;
};
union TValue {
    // The unnamed structs are needed because otherwise the compiler does not accept it...
    bool                Bit;
    struct{ TNumeric    Numeric; };
    struct{ wstring     Text; };
};

TNumeric Numeric;
TNumeric &rNumeric{ Numeric };
rNumeric.Integral = L"";
rNumeric.Integral.push_back( L'X' ); //OK, no problem

TValue Value;
TValue &rValue{ Value };
rValue.Text = L"";
rValue.Text.push_back( L'X' ); //OK, no problem

rValue.Numeric.Integral = L"";
rValue.Numeric.Integral.push_back( L'X' ); // Exception

In release mode there is no problem. When run in debug mode there is an exception at the last statement in method _Adopt of class _Iterator_base12 in xutility: Access violation reading location 0x0000005C.

In _Adopt the code is only run when _ITERATOR_DEBUG_LEVEL == 2. I tried with

#define _ITERATOR_DEBUG_LEVEL 1

added in my main program but it remains defined as 2. Is there a way to disable the check?

1

There are 1 answers

2
Anton Savin On BEST ANSWER

VS 2013 doesn't support C++11 unrestricted unions, that is it implements unions as per C++03:

An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union

You successfully fooled the compiler by using unnamed structs, but that doesn't solve the problem: the objects are non-trivial, and VS2013 doesn't support that.

When you switch to more C++11-compliant compiler, such as VS 2015, you'll have to implement constructor, destructor, copy constructor etc. for the union in a way that it safely constructs/destructs/copies appropriate part of the union. There's an example in the standard (I'm quoting C++14 draft N4140 [class.union]/4):

Consider an object u of a union type U having non-static data members m of type M and n of type N. If M has a non-trivial destructor and N has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of u can be safely switched from m to n using the destructor and placement new operator as follows:

u.m.~M();
new (&u.n) N;