Why would one wrap a struct in an anonymous union? (STL msvc implementation)

Viewed 173

The STL <memory> header (MSVC implementation) contains a class called:

template <class _Ty> class _Ref_count_obj2 : public _Ref_count_base

This class has a member:

union {
    _Wrap<_Ty> _Storage;
};

where _Wrap is defined as:

template <class _Ty> 
struct _Wrap {
    _Ty _Value; // workaround for "T^ is not allowed in a union"
};

From my understanding, this code is designed to hold an object of type _Ty following its construction via the new operator. However I can't figure out why this was done; it seems like using a struct instead of a struct inside a union would work just as well.

Can anyone explain the reasoning behind this? Also, can anyone explain the comment in the _Wrap definition?

1 Answers

First, embedding the _Storage member in a union will prevent default destruction of that object (which is, more than likely, a non-trivial type); this appears to be essential, as the class involved is a reference counter. (By default, unions have a deleted destructor; see, for example: Is a Union Member's Destructor Called .)

Second, using an anonymous union 'moves' the _Storage identifier into the enclosing scope, thus removing any need for X.-style notation (if the union were to be named X). From cppreference:

Members of an anonymous union are injected in the enclosing scope (and must not conflict with other names declared there).

Last, the need to wrap the union's member into a templated structure is so that the class will work with reference types, which are not allowed in unions. To check this last part out, try the following code with the commented-out lines made active:

template <class _Ty>
struct _Wrap {
    _Ty _Value; // workaround for "T^ is not allowed in a union"
};

template<class T>
class bob {
public:
    bob(T t) : uncle{t}//, aunty(t)
    {
    }
private:
    union {
        _Wrap<T> uncle;
    };
//    union {
//        T aunty;
//    };
};

int main()
{
    int i = 42;
    bob<int&> b{ i }; // Note: Template uses a REFERENCE type
    return 0;
}
Related