下面是来自Loki 单例实现的一段代码,它展示了所谓的“MaxAlign Trick”。我认为它与对齐有关(废话!),但是尝试与联合内提到的所有类型对齐的目的是什么?如果没有它,
Create()
内的新放置会破坏吗?
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
有两个目的。首先,它是 C++11 std::max_align_t
的实现:“一种简单的标准布局类型,其对齐要求至少与每个标量类型一样严格(一样大)”。 (cppreference)。由于类型的对齐是具有最高对齐要求的数据成员的对齐,因此 MaxAlign
的定义准确地为我们提供了:保证具有最大值的类型。与感兴趣的平台保持一致。
其次,它也是一个足够大以包含
T
的缓冲区:
char t_[sizeof(T)];
从这两个方面来看,
MaxAlign
提供了C++11功能std::aligned_storage_t<size, alignment>
(不考虑T
的过度对齐 - 当时它可能甚至不存在)。
但是为什么需要它:放置
new
需要缓冲区针对正在构造的实例进行适当对齐。如果没有这种“对齐技巧”,您可能会得到未定义的行为。 T
作为一种未知类型,Loki 通过选择代码编译平台的最大对齐来规避任何风险。
在现代代码中,您可能不会使用放置 new,而是在堆栈上使用
static
对象,例如
static T& Create() {
static T instance;
return instance;
}
但是在 20 年前,这可能无法在跨编译器和/或多线程环境中正常工作(自 C++11 IIRC 起只能保证上述
T instance
的正确初始化)。