Почему стандарт C ++ допускает несовместимость std :: max_align_t и __STDCPP_DEFAULT_NEW_ALIGNMENT__? - PullRequest
0 голосов
/ 16 мая 2019

В 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;};

вызовет стандартный оператор new (без аргумента std::align_val_t)и ожидайте, что он будет выровнен на 16 байтов, в то время как std::max_align_t указывает только, что он должен быть выровнен на 8 байтах.

Это означает, что при переопределении операторов new вы вынуждены выровнять все наминимум 16 байтов, даже если 8 байтов будет достаточно.

  • Я что-то упустил?
  • Это ошибка в способе реализации Visual Studio C ++ / STL?
  • Или это ошибка в стандарте C ++ / STL?

1 Ответ

1 голос
/ 16 мая 2019

В C ++ 17 есть два уровня переопределенных типов: расширенный и новый расширенный. 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 new этого объекта, чтобы напрямую вызвать специфичное для выравнивания operator new. Но вы не можете заставить компилятор сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...