为什么 C++ 标准允许 std::max_align_t 和 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 不一致?

Pat*_*ick 7 c++ c++-standard-library visual-studio

在 Visual Studio 中,编译 64 位时:

  • sizeof(std::max_align_t) 是 8
  • __STDCPP_DEFAULT_NEW_ALIGNMENT__ 是 16

因此,尽管std::max_align_t表示 的实现new应该返回对齐到 8 个字节的倍数的指针,但对齐要求为 16 个字节的分配不会调用该void* operator new (std::size_t count, std::align_val_t);方法,而是调用void* operator new (std::size_t count);(参见https://en.cppreference.com/w/cpp/memory /new/operator_new ) 并期望它们返回一个 16 字节对齐的指针。

所以分配一个这样定义的结构:

struct alignas(16) S {double m_value;};
Run Code Online (Sandbox Code Playgroud)

将调用标准运算符new(不带std::align_val_t参数)并期望它在 16 个字节上对齐,而std::max_align_t只指定它应该在 8 个字节上对齐。

这意味着当否决new运算符时,您必须将所有内容对齐至少 16 个字节,即使 8 个字节就足够了。

  • 我错过了什么吗?
  • 这是 Visual Studio 实现 C++/STL 方式的错误吗?
  • 或者这是 C++/STL 标准中的错误?

Nic*_*las 6

C++17 中有两层过度对齐的类型:extended 和 new-extended。std::max_align_t定义未扩展__STDCPP_DEFAULT_NEW_ALIGNMENT__的最大对齐,并定义未新扩展的最大对齐。

顾名思义,新扩展对齐是关于你用new.

基本上,常规operator new将返回适合任何对象的内存,直到新扩展的对齐大小。任何更大的对齐都更喜欢使用operator new指定正在创建的类型的对齐方式的重载。当然,就像一般的过度对齐类型一样,有条件地支持。operator delete销毁与此类类型关联的内存的调用也是如此。

Visual Studio 所说的是不被视为过度对齐的最大对齐是 8 字节,但分配的内存对齐operator new是 16 字节。


这意味着当否决new运算符时,您必须将所有内容对齐至少 16 个字节,即使 8 个字节就足够了。

基本上,是的。没有办法要求实现告诉您原始operator new/delete重载所请求的对齐方式。

现在,您可以逐个对象地重载该对象operator newoperator new直接调用特定于对齐的对齐方式。但是你不能让编译器这样做。

  • @Patrick:“*而 std::max_align_t 声明它必须是 8 个字节。*”它没有声明这样的事情。这只是类型被认为具有扩展对齐之前的最大大小。它没有说明从“operator new”返回的指针的对齐方式。 (2认同)