I'm using std::aligned_storage
as the backing storage for a variant template. The problem is, once I enable -O2
on gcc I start getting warnings of 'dereferencing type-punned pointer will break strict aliasing`.
The real template is much more complex (type checked at runtime), but a minimal example to generate the warning is:
struct foo
{
std::aligned_storage<1024> data;
// ... set() uses placement new, stores type information etc ...
template <class T>
T& get()
{
return reinterpret_cast<T&>(data); // warning: breaks strict aliasing rules
}
};
I'm pretty sure boost::variant
is doing essentially the same thing as this, but I can't seem to find how they avoid this issue.
My questions are:
- If using
aligned_storage
in this way violates strict-aliasing, how should I be using it? - Is there actually a strict-aliasing problem in
get()
given that there are no other pointer based operations in the function?- What about if
get()
is inlined? - What about
get() = 4; get() = 3.2
? Could that sequence be reordered due toint
andfloat
being different types?
- What about if
std::aligned_storage
is part of<type_traits>
; like most of the rest of the inhabitants of that header file, it is just a holder for some typedefs and is not meant to be used as a datatype. Its job is to take a size and alignment, and make you a POD type with those characteristics.You cannot use
std::aligned_storage<Len, Align>
directly. You must usestd::aligned_storage<Len, Align>::type
, the transformed type, which is "a POD type suitable for for use as uninitialized storage for any object whose size is at mostLen
and whose alignment is a divisor ofAlign
." (Align
defaults to the largest useful alignment greater than or equal toLen
.)As the C++ standard notes, normally the type returned by
std::aligned_storage
will be an array (of the specified size) ofunsigned char
with an alignment specifier. That avoids the "no strict aliasing" rule because a character type may alias any other type.So you might do something like: