TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #1033 3.72K
​​alignas
#опытным

Ну хорошо. Мы поняли, что такое выравнивание, как компилятор добавляет паддинги и как узнать требования к выравниванию для типа.

Да, в основном компилятор управляет выравниваем. Но компилятор не знает всех тонкостей работы вашей программы. И не всегда корректно может выровнять данные.

В мире С++ можно контролировать почти все и alignment не исключение. Мы можем сами своими руками указать компилятору, как нужно выровнять конкретные тип.

Для этого существует C++11 спецификатор alignas. Он применяется к объявления типа или переменной и устанавливает новые требования для их выравнивания.

Сравним:

struct Vector4 {
float x, y, z, w;
};
struct alignas(16) Vector4Aligned {
float x, y, z, w;
};

std::cout << "Alignment of Vector4 is " << alignof(Vector4) << std::endl;
std::cout << "Alignment of Vector4Aligned is " << alignof(Vector4Aligned) << std::endl;

float data[8] = {1, 2, 3, 4, 5, 6, 7, 8};
alignas(32) float aligned_data[8] = {1, 2, 3, 4, 5, 6, 7, 8};

std::cout << "Alignment of data is " << alignof(data) << std::endl;
std::cout << "Alignment of aligned_data is " << alignof(aligned_data) << std::endl;
// OUTPUT:
// Alignment of Vector4 is 4
// Alignment of Vector4Aligned is 16
// Alignment of data is 4
// Alignment of aligned_data is 32


Без alignas данные выровнены по границе 4, как это нужно типу float. Используя же спецификатор, мы можем изменить требования.

Можно также выровнять данные на основе другого типа:

struct alignas(float) struct_float
{
// ...
};


Заметьте кстати, что в предыдущих примерах размер данных не изменялся, потому что мы выровняли по границе размера данных. Но можно же использовать и более сильные требования:

struct alignas(32) Vector4AlignedTooMuch {
float x, y, z, w;
};

std::cout << "Alignment of Vector4AlignedTooMuch is "
<< alignof(Vector4AlignedTooMuch) << ", and size is "
<< sizeof(Vector4AlignedTooMuch) << std::endl;
// OUTPUT:
// Alignment of Vector4AlignedTooMuch is 32, and size is 32


В этом случае размер данных увеличился в соответствие с усиленным выравниванием и добавлением паддингов.

Выравнивание переменных же аффектит только их адрес, потому что тип уже фиксирован.

Получается, что в определенных случаях мы тратим дополнительную память в угоду выравниванию. Зачем это может быть нужно?

Например, у вас есть массив мьютексов, которым пользуются разные потоки.

У каждого ядра есть свои кэш-линии для того, чтобы быстрее работать с медленной оперативной памятью. И потоки, которые получают доступ к массиву, сохраняют в кэш линию своего ядра этот массив. Получается, что потенциально в нескольких кэш-линиях будут находиться семантически одни и те же расшаренные данные.

Что будет, если одно из ядер изменит хотя бы один мьютекс? Кэш линии других ядер инвалидируются и заново будут загружаться из ОП. А это очень долго. И так будет повторяться при каждом захвате и отпускании замка.

Такая ситуация называется false sharing. Вы ожидаете, что данные не связаны и независимы, а на самом деле операции над одними данными влияют на другие.

В этом случае поможет выравнивание данных по границе размера кэш линии:

struct AlignedMutex
{
alignas(64) std::mutex mutex;
};
std::array<AlignedMutex, 10> mutexes;


Тогда каждый мьютекс будет в своей кэш-линии и операции над одним из них не будут инвалидировать соседние кэш-линии.

Другой пример использования alignas - векторные инструкции sse и avx. Современные процессоры имеют специальные инструкции для обработки нескольких данных одновременно. Этими инструкциями управляются данные в векторных регистрах, их длины - это 128, 256 или 512 бит. Для более быстрой загрузки данные должны быть выровнены по ширине соответствующих векторных регистров:

alignas(32) float aligned_data[8] = {1.0f, 2.0f, 3.0f, 4.0f, 
5.0f, 6.0f, 7.0f, 8.0f}
__m256 avx_reg = _mm256_load_ps(aligned_data);


В общем, очень полезная штука, must have to know.

Have your separate space. Stay cool.

#cppcore #cpp11 #compiler
  • ❤ 23
  • 🔥 12
  • 👍 8
  • 🎉 2
  • 👏 1
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →