Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the C++ standard allow std::max_align_t and __STDCPP_DEFAULT_NEW_ALIGNMENT__ to be inconsistent?

In Visual Studio, when compiling 64-bit:

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

So although std::max_align_t indicates that implementations of new should return pointers aligned to a multiple of 8 bytes, allocations with an alignment requirement of 16 bytes don't call the void* operator new (std::size_t count, std::align_val_t); method but call void* operator new (std::size_t count); (see https://en.cppreference.com/w/cpp/memory/new/operator_new) and expect them to return a pointer aligned on 16 bytes.

So allocating a struct defined like this:

struct alignas(16) S {double m_value;};

will call the standard operator new (without std::align_val_t argument) and expect it to be aligned on 16 bytes, while std::max_align_t only specifies that it should be aligned on 8 bytes.

This means that when overruling the new operators, you are forced to align everything on at least 16 bytes, even if 8 bytes would be sufficient.

  • Am I missing something?
  • Is this an error in the way Visual Studio implements C++/STL?
  • Or is this an error in the C++/STL standard?
like image 471
Patrick Avatar asked May 16 '19 14:05

Patrick


1 Answers

There are two layers of over-aligned types in C++17: extended and new-extended. std::max_align_t defines the largest alignment that is not extended, and __STDCPP_DEFAULT_NEW_ALIGNMENT__ defines the largest alignment that is not new-extended.

New-extended alignment, as the name suggests, is about the alignment of things you allocate with new.

Basically, the regular operator new will return memory suitable for any object up to the new-extended alignment size. Any greater alignment prefers the use of operator new overloads that specify the alignment of the type being created. And of course, are conditionally supported just like over-aligned types in general. The same goes for the operator delete calls to destroy the memory associated with such types.

What Visual Studio is saying is that the maximum alignment that is not considered over-aligned is 8-byte, but the alignment for memory allocated by operator new is 16-byte.


This means that when overruling the new operators, you are forced to align everything on at least 16 bytes, even if 8 bytes would be sufficient.

Essentially, yes. There's no way to request that the implementation tell you what alignment is being requested with the raw operator new/delete overloads.

Now, you can, on an object-by-object basis, overload that object's operator new to invoke the alignment-specific operator new directly. But you can't make the compiler do so.

like image 126
Nicol Bolas Avatar answered Nov 04 '22 07:11

Nicol Bolas