为什么在std::aligned_storage_t
中定义了对扩展对齐实现的支持?指定在内部适当大小的缓冲区上使用alignas()
的实现应该很容易?
答案 0 :(得分:2)
对扩展对齐的所有支持为implementation defined:
由实现方式定义是否支持任何扩展的对齐方式以及支持它们的上下文。
已添加重点。
一个实现可以自由地在某些地方而不是其他地方支持扩展的对齐方式。可以创建具有扩展对齐方式的堆对象,但不能创建堆栈对象(或作为堆栈变量的子对象)。 aligned_storage
仅仅是另一个上下文。
为什么[扩展对齐]是在某些应该定义得很好的环境中定义的(例如堆栈内存)?
考虑堆分配与堆栈分配的实现负担。
有了堆分配,编译器需要做什么才能使new OverAlignedType
工作? C ++ 17之前的版本?它什么都不需要。 ::operator new
要么恰好会分配适合该对齐方式的存储,要么会分配未定义的行为结果。编译器对此没有任何控制。放置位置也是如此-new
;在这种情况下,取决于用户是否正确对齐。
C ++ 17添加了operator new
的对齐形式。但是即使那样,唯一的区别是调用了哪个版本的函数。对于编译器而言,这是微不足道的。
现在考虑堆栈分配。我创建了一个类型为OverAlignedType
的变量。好的,那如何实现呢?显然,编译器根据堆栈上的先前分配来查看堆栈偏移量在函数中该点的位置。然后-
错误!为什么?因为在该函数调用中堆栈开始的实际地址的对齐方式可能不适用于该类型。请记住:对于任何给定的函数调用,堆栈地址将基于当前调用图所基于的内容。如果您的OverAlignedType
需要32字节的对齐方式,而ABI仅需要16字节的对齐方式来开始堆栈,则很有可能有时用户碰巧在堆栈将位于堆栈顶部时调用它。 32字节边界,有时仅为16字节。
那你怎么办?好了,您必须执行一些运行时代码才能查看实际的堆栈地址并在需要的地方对齐它。请注意,这会将静态的编译时偏移量转换为动态的偏移量。这也可能会影响该函数中每个堆栈对象的放置。
或者您也可以禁止用户在堆栈上使用过度对齐的类型。