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++17new
типов, которые требуют большего выравнивания, чем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 байта. По более ранним стандартам это было не так.