如何对齐std :: array包含的数据?

Har*_*ald 11 c++ arrays std memory-alignment c++11

既然std::array不允许更改其分配器,是否有办法确保指向数据地址的指针是对齐的?

例如,在GNU g ++ 4.8.4和6.1.0中,代码如下

#include <array>
#include <iostream>

int main(void)
{
  std::array<bool, 10> a;
  std::array<char, 10> b;
  std::array<int,10> c;
  std::array<long long, 10> d;
  std::array<float, 10> e;
  std::array<double, 10> f;

  std::cout << "array<bool,10>.data()       = " << a.data() << std::endl;
  std::cout << "array<char,10>.data()       = " << (void*) b.data() << std::endl;
  std::cout << "array<int,10>.data()        = " << c.data() << std::endl;
  std::cout << "array<long long, 10>.data() = " << d.data() << std::endl;
  std::cout << "array<float, 10>.data()     = " << e.data() << std::endl;
  std::cout << "array<double, 10>.data()    = " << f.data() << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

提供以下输出,显示容器数据与16字节地址对齐,无论编译x86-64位体系结构时包含的数据类型如何.

array<bool,10>.data()       = 0x7ffe660a2e40
array<char,10>.data()       = 0x7ffe660a2e30
array<int,10>.data()        = 0x7ffe660a2e00
array<long long, 10>.data() = 0x7ffe660a2db0
array<float, 10>.data()     = 0x7ffe660a2d80
array<double, 10>.data()    = 0x7ffe660a2d30
Run Code Online (Sandbox Code Playgroud)

但是,对于Intel的icpc v16.0.3,结果如下所示,即使使用-align.虽然大多数容器与16字节地址对齐,但是一些(char和float数组)与较小的字节地址(分别为2字节和8字节)对齐.

array<bool,10>.data()       = 0x7ffdedcb6bf0
array<char,10>.data()       = 0x7ffdedcb6bfa
array<int,10>.data()        = 0x7ffdedcb6ba0
array<long long, 10>.data() = 0x7ffdedcb6b00
array<float, 10>.data()     = 0x7ffdedcb6bc8
array<double, 10>.data()    = 0x7ffdedcb6b50
Run Code Online (Sandbox Code Playgroud)

编辑

仅举例说明RustyX的提议,这是更改的代码

#include <array>
#include <iostream>

int main(void)
{
  alignas(16) std::array<bool, 10> a;
  alignas(16) std::array<char, 10> b;
  alignas(16) std::array<int,10> c;
  alignas(16) std::array<long long, 10> d;
  alignas(16) std::array<float, 10> e;
  alignas(16) std::array<double, 10> f;

  std::cout << "array<bool,10>.data()       = " << a.data() << std::endl;
  std::cout << "array<char,10>.data()       = " << (void*) b.data() << std::endl;
  std::cout << "array<int,10>.data()        = " << c.data() << std::endl;
  std::cout << "array<long long, 10>.data() = " << d.data() << std::endl;
  std::cout << "array<float, 10>.data()     = " << e.data() << std::endl;
  std::cout << "array<double, 10>.data()    = " << f.data() << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是使用英特尔icpc v16.0.3进行编译时的结果.

array<bool,10>.data()       = 0x7ffe42433500
array<char,10>.data()       = 0x7ffe42433510
array<int,10>.data()        = 0x7ffe424334a0
array<long long, 10>.data() = 0x7ffe42433400
array<float, 10>.data()     = 0x7ffe424334d0
array<double, 10>.data()    = 0x7ffe42433450
Run Code Online (Sandbox Code Playgroud)

rus*_*tyx 14

默认情况下,编译器在对齐时会做正确的事情.

但你可以用alignas以下方式覆盖它:

alignas(16) std::array<char, 10> b;
Run Code Online (Sandbox Code Playgroud)

Postscriptum

有趣的是,英特尔编译器认为对齐char[]8字节就足够了.就好像它知道在x86平台上你通过更宽的对齐获得很少.

请记住,过多的对齐可能会因内存使用量增加和缓存效率降低而降低性能.现代x86架构(Sandy Bridge和更新版本)使用未对齐的数据非常有效,但无法补偿部分使用的缓存行(更多信息).

  • `std :: array`只包含元素的数组.如果对齐它,也可以对齐底层数组. (2认同)