Following a snippet of code from Loki singleton implementation which shows what it calls "MaxAlign Trick". I assume it has something to do with alignment (duh!), but what's the purpose of trying to align with all the types mentioned inside the union? Will the placement new inside Create()
break without it?
template <class T> struct CreateStatic
{
union MaxAlign
{
char t_[sizeof(T)];
short int shortInt_;
int int_;
long int longInt_;
float float_;
double double_;
long double longDouble_;
struct Test;
int Test::* pMember_;
int (Test::*pMemberFn_)(int);
};
static T* Create()
{
static MaxAlign staticMemory_;
return new(&staticMemory_) T;
}
// other code...
}
MaxAlign
serves two purposes. First, it is an implementation of the C++11 std::max_align_t
: "a trivial standard-layout type whose alignment requirement is at least as strict (as large) as that of every scalar type." (cppreference). Since the alignment of a type is the alignment of the data member with the highest alignment requirements, the definition of MaxAlign
gives us exactly that: a type that is guaranteed to have the max. alignment for the platform of interest.
Second, it is also a buffer that is large enough to contain a T
:
char t_[sizeof(T)];
Taking both aspects, MaxAlign
provides the C++11 feature std::aligned_storage_t<size, alignment>
(without taking over-alignment of T
is into account - it probably didn't even exist back then).
But why is it needed: placement new
requires the buffer to be suitably aligned for the instance that is being constructed. Without this "alignment trick", you might end up with undefined behaviour. T
being an unkonwn type, Loki circumvents any risks by choosing the maximal alignment for the platform the code is being compiled for.
In modern code, you would probably not use placement new, but use a static
object on the stack, e.g.
static T& Create() {
static T instance;
return instance;
}
But 20 years ago, this might not have worked properly across compilers and/or in multi-threaded environments (proper initialisation of T instance
in the above is only guaranteed since C++11 IIRC).