__STDCPP_DEFAULT_NEW_ALIGNMENT__和alignof(std :: max_align_t)之间的顺序

时间:2019-12-04 09:03:02

标签: c++ language-lawyer c++17 new-operator memory-alignment

在x86-64 / Linux上使用GCC和Clang时,alignof(std::max_align_t)__STDCPP_DEFAULT_NEW_ALIGNMENT__都等于16

在x86-64 / Windows上使用MSVC的情况下,alignof(std::max_align_t)8,而__STDCPP_DEFAULT_NEW_ALIGNMENT__16

该标准在[basic.align]/3中定义了与这些数量相对应的两个术语:

  

扩展的比对由大于alignof(std​::​max_­align_­t)的比对表示。 [...]具有扩展对齐要求的类型是过度对齐类型。 [...] 新扩展的比对由大于_­_­STDCPP_­DEFAULT_­NEW_­ALIGNMENT_­_­的比对表示。

除非我将术语“ new-extended ”解释为暗含“ extended ”,否则我认为这并不意味着两个值之间有任何顺序。拼写。

是允许的C ++标准的符合性实现

alignof(std::max_align_t) > __STDCPP_DEFAULT_NEW_ALIGNMENT__

如果这样做,是否暗示通过以下方式创建对象

auto x = ::new(::operator new(sizeof(T))) T;

对于某些未过度对齐的类型T,可能是未定义的行为吗?

1 个答案:

答案 0 :(得分:2)

如果我没看错标准,则新扩展的比对是指void* operator new( std::size_t count, std::align_val_t al);的所有变体(带有std::align_val_t的变体)。

因此,假设__STDCPP_DEFAULT_NEW_ALIGNMENT__为8,std::max_align_t为16,则long double的分配将必须调用::operator new(16, std::align_val_t(16));。编译器在不引起您注意的情况下将为您做些事情。

实际上,我相信有一些Linux实现可以保证新的对齐方式为8。(moz)jemalloc是其中之一,为此,github-issue似乎确认最小对齐方式为8而不是16(我没有找到有关它的官方文档)

如果要使用这种实现,则必须更新__STDCPP_DEFAULT_NEW_ALIGNMENT__常量,有关更多详细信息,请参阅我的问题之一:Overloading operator new with smaller default alignment

要回答您的最后一个问题,我读了auto x = ::new(::operator new(sizeof(T))) T;,明确地将运算符称为new,而不是简单地进行new T,在这种情况下,如果T要求的对齐方式大于默认的新对齐方式。请注意,如果两个常量相等,这也适用,因为您可以在类中添加alignas来更改对齐方式。

使用这些类需要格外小心,因为在与std::vector一起使用时使用自定义分配器。