确定C++中最大可能的对齐方式

jal*_*alf 21 c++ alignment c++11

是否有任何可移植的方法来确定任何类型的最大可能对齐方式是什么?

例如,在x86上,SSE指令需要16字节对齐,但据我所知,没有指令需要更多,因此任何类型都可以安全地存储到16字节对齐的缓冲区中.

我需要创建一个缓冲区(例如char数组),我可以在其中编写任意类型的对象,因此我需要能够依赖缓冲区的开头进行对齐.

如果一切都失败了,我知道,分配使用char数组new保证具有最大对齐,而是与TR1/C++ 0x中的模板alignment_ofaligned_storage,我想知道是否有可能在我的缓冲创建就地缓冲区类,而不是要求动态分配的数组的额外指针间接.

想法?

我意识到有很多选项可以确定有界类型的最大对齐:一个联合,或者只是alignment_of来自TR1,但我的问题是类型集是无界的.我事先并不知道哪些对象必须存储到缓冲区中.

Ric*_*y65 12

在C++ 11中,头文件cstddef中定义的std :: max_align_t是一种POD类型,其对齐要求至少与每个标量类型的对齐要求一样严格(大).

使用新的alignof运算符就可以了 alignof(std::max_align_t)


Jam*_*lis 10

在C++ 0x中,Align模板参数的std::aligned_storage<Len, Align>默认参数为"default-alignment",定义为(N3225§20.7.6.6表56):

对于任何大小不大于的C++对象类型,default-alignment的值应该是最严格的对齐要求Len.

目前尚不清楚SSE类型是否会被视为"C++对象类型".

默认参数不是TR1的一部分aligned_storage; 它是为C++ 0x添加的.


sti*_*472 6

不幸的是,确保最大对齐比它应该更加困难,并且没有保证的解决方案AFAIK.来自GotW博客(Fast Pimpl文章):

union max_align {
  short       dummy0;
  long        dummy1;
  double      dummy2;
  long double dummy3;
  void*       dummy4;
  /*...and pointers to functions, pointers to
       member functions, pointers to member data,
       pointers to classes, eye of newt, ...*/
};

union {
  max_align m;
  char x_[sizeofx];
};
Run Code Online (Sandbox Code Playgroud)

这不能保证完全可移植,但实际上它足够接近,因为很少或没有系统不能按预期工作.

这就是我所知道的最接近的'黑客'.

还有另一种我亲自用于超快速分配的方法.请注意,这是邪恶的,但我在光线追踪领域工作,速度是最好的质量衡量标准之一,我们每天都会编码.它涉及使用具有预分配内存的堆分配器,其工作方式类似于本地堆栈(仅在分配时递增指针并在解除分配时递减1).

我特别把它用于Pimpls.但是,仅仅拥有分配器是不够的; 为了让这样的分配器工作,我们必须假设一个类Foo的内存在构造函数中分配,同样的内存同样只在析构函数中释放,并且Foo本身是在堆栈上创建的.为了安全起见,我需要一个函数来查看类的'this'指针是否在本地堆栈上,以确定我们是否可以使用我们的超快速堆栈堆栈分配器.为此,我们必须研究特定于操作系统的解决方案:我在Win32/Win64上使用了TIBTEB,我的同事找到了Linux和Mac OS X的解决方案.

结果,在研究了特定于OS的方法来检测堆栈范围,对齐要求以及进行大量测试和分析之后,一个分配器可以根据我们的滴答计数器基准在4个时钟周期内分配内存,而不是malloc/operator new有400个周期(我们的测试涉及线程争用,因此在单线程情况下malloc可能比这个快一点,可能是几百个周期).我们添加了一个每线程堆栈并检测到正在使用哪个线程,这将时间增加到大约12个周期,尽管客户端可以跟踪线程分配器以获得4个周期分配.它消除了地图上基于内存分配的热点.

虽然您不必经历所有这些麻烦,但编写快速分配器可能更容易且更普遍适用(例如:允许在运行时确定分配/解除分配的内存量),而不是像max_align这里那样.max_align很容易使用,但是如果你的内存分配速度很快(假设你已经分析了你的代码并发现malloc/free/operator new/delete中的热点,主要贡献者在代码中你可以控制),编写自己的分配器可以真正发挥作用.


Dav*_*ler 5

maximally_aligned_t所有编译器都承诺忠实地支持所有架构的某种类型,我不知道如何在编译时解决这个问题.如你所说,潜在类型的集合是无限的.额外的指针间接是真的那么重要吗?