我正在浏览一些新的C ++ 14特性,aligned_storage引起了我的注意,在谈到并发性,局部性和数据结构对齐之后,我想到了内存块的事实为std::vector
分配的内容保证在内存中是连续的,但这并不一定意味着向量本身是有效打包的,或者更好地说,您关心的数据是有效对齐的,可能有额外的关于该数据结构的信息,不一定对计算有用,并且可能会干扰您的数据。
所以我问,如果我有一个class T
并且我知道T
已按照我喜欢的方式对齐和打包,std::vector<T>
将缓存友好并在管道中对齐?
我的问题涉及C ++ 11和C ++ 14,它只涉及数据结构布局,我没有考虑与缓存行的组织相关的其他问题,例如虚假共享,或者与事情如何获得有关的其他问题获取,加载和执行。
我知道这听起来很傻,但我只是怀疑。
答案 0 :(得分:1)
C ++默认分配器需要对齐任何所谓的标准类型正确对齐的结构,并且在结构的末尾自动添加的填充(通过sizeof()
可见)通常在连续分配中促进这一点。 强>
struct C {
uint8_t a; // followed by 7B of invisible padding to naturally align b
uint64_t b;
uint32_t c;
uint8_t d; // followed by 3B padding for C (natural alignment of 8B due to b)
};
// sizeof(C) = 24B, alignof(C) = 8B
struct D {
uint8_t a; // followed by 3B padding for b
uint32_t b;
uint8_t c; // followed by 3B padding for D (natural alignment of 4B due to b)
};
// sizeof(D) = 12B, alignof(D) = 4B
struct E {
__m256 v; // SSE/AVX intrinsics handle natural alignment properly too
char v2;
};
// sizeof(E) = 64B, alignof(E) = 32B
对于大多数情况,这是足够的,但如果您正在进行花哨的强制转换技巧或需要64B缓存行对齐等,您可以使用alignas()
,前提是您使用的是C ++ 11或较新的即可。这也可以通过填充结构的末端来实现:
struct alignas(64) F {
double stuff[3];
};
// sizeof(F) = 64B, alignof(F) = 64B
void foo() {
F f[4];
// these addresses separated by (and even multiples of) 0x40 bytes:
cout << &f[0] << " " << &f[1] << " " << &f[2] << endl;
}
如果您需要与例如4 kiB页边界对齐的大块,请使用std::aligned_storage<T>
。但是,一般情况下,您只能使用展示位置new
自行处理,并失去std::vector<>
为您完成所有工作的便利。