在 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 和 alignof(std::max_align_

Order between __STDCPP_DEFAULT_NEW_ALIGNMENT__ and alignof(std::max_align_t)

本文关键字:std max align alignof STDCPP DEFAULT NEW ALIGNMENT      更新时间:2023-10-16

在x86-64/Linux上,GCC和Clangalignof(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_­_­的对齐方式表示。

我不认为这意味着两个值之间的任何排序,除非我将术语">扩展"解释为拼写中的">扩展"。

是否允许具有C++标准的符合实现

alignof(std::max_align_t) > __STDCPP_DEFAULT_NEW_ALIGNMENT__

如果是这样,这是否意味着通过

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

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

  • std::max_align_t:最大标量类型的对齐方式
  • __STDCPP_DEFAULT_NEW_ALIGNMENT__:分配内存的对齐方式

如果我正确阅读标准,则新扩展的对齐方式是指void* operator new( std::size_t count, std::align_val_t al);的所有变体(带有std::align_val_t的变体(。

所以假设__STDCPP_DEFAULT_NEW_ALIGNMENT__8,std::max_align_t16,长双的分配就得叫::operator new(16, std::align_val_t(16));。您的编译器必须在您不注意的情况下为您执行一些操作。

在实践中,我相信有一些 linux 实现可以保证新的 8 对齐。(Moz(Jemalloc 就是其中之一,这个 github 问题似乎证实了最小对齐方式是 8 而不是 16。(我没有找到有关它的官方文档(

如果要使用此类实现,则必须更新__STDCPP_DEFAULT_NEW_ALIGNMENT__常量,有关更多详细信息,请参阅我的一个问题:重载运算符新,默认对齐方式较小。

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

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