gcc выровнял новую поддержку (alignas)

У меня возникают трудности с поиском дополнительной информации о выровненном новом предупреждении GCC и опции gcc -faligned-new. Компиляция на gcc 7.2.0 (без --std= C++17) и попытка определить выровненную структуру, такую ​​как:

struct alignas(64) Foo { int x; }

Просто делаю старый добрый

Foo * f = new Foo();

Дает мне следующее предупреждение и предложение:

 alignas.cpp:36:25: warning: ‘new’ of type ‘Foo’ with extended alignment 64 [-Waligned-new=]
 Foo * f = new Foo();
                     ^
 alignas.cpp:36:25: note: uses ‘void* operator new(long unsigned int)’, which does not have an alignment parameter
 alignas.cpp:36:25: note: use ‘-faligned-new’ to enable C++17 over-aligned new support

Я так понимаю по умолчанию new вернет только память, выровненную до alignof( std::max_align_t ) (для меня это 16), но что мне не ясно, так это то, что если я передам -faligned-new, gcc теперь принудительно установит правильное новое выравнивание new от моего имени?

К сожалению, документации gcc по этому вопросу крайне не хватает.

1 ответ

Решение

Из руководства gcc:

-faligned новый
Включить поддержку C++17 new типов, которые требуют большего выравнивания, чем void* ::operator new(std::size_t) обеспечивает. Числовой аргумент, такой как -faligned-new=32, может использоваться для указания того, сколько выравнивания (в байтах) предоставляется этой функцией, но немногим пользователям потребуется переопределить значение по умолчанию для alignof(std::max_align_t),

Это означает, что -faligned-new просто делает новые функции выравнивания, добавленные в P0035R4, доступными без полной поддержки C++17.

Соответствующие биты из стандарта C++:
Из [cpp.predefined]:

__STDCPP_DEFAULT_NEW_ALIGNMENT__
Целочисленный литерал типа std::size_t значение которого является выравниванием, гарантированным вызовом operator new(std::size_t) или же operator new[](std::size_t), [Примечание: большие выравнивания будут переданы operator new(std::size_t, std::align_val_t)и т. д. (8.3.4). - конец примечания]

Из [basic.align/3]:

Новое расширенное выравнивание представлено выравниванием, большим чем __STDCPP_DEFAULT_NEW_ALIGNMENT__

А с [expr.new/14]:

Разрешение перегрузки выполняется для вызова функции, созданной путем сборки списка аргументов. Первый аргумент - это количество запрошенного пространства, и он имеет тип std::size_t, Если тип выделенного объекта имеет новое расширенное выравнивание, следующий аргумент является выравниванием типа и имеет тип std::align_val_t,


Так что в вашем случае с C++17 или -faligned-new, так как Foo имеет новое расширенное выравнивание, Foo* f = new Foo(); позвоню void* operator new(size_t, align_val_t) выделить память и вернуть указатель на Foo объект, который правильно выровнен на границе 64 байта. По более ранним стандартам это было не так.

Другие вопросы по тегам