TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #273 3.74K
​Динамическая инициализация

После статической инициализации в компайлтайме идет динамическая инициализация в рантайме. Хотелось бы сказать, что хоть здесь простой и понятный порядок, но нет. Это глобальные переменные и С++, поэтому будет немного больно.

Динамическая инициализация разделяется на 3 подгруппы:

1️⃣ Неупорядоченная динамическая инициализация. Она применяется только для статических полей шаблонных классов и шаблонных переменных, которые не специализированы явно(явно специализированные шаблоны - обычные классы). И вот порядок установки значений этих сущностей вообще неопределен. Куда понравится компилятору, туда и вставит.

2️⃣ Частично упорядоченная инициализация. Применяется для всех нешаблонных инлайн переменных. Есть 2 переменные: inline переменная А и В, которая не подходит под критерии применения первой подгруппы. Если А определена во всех единицах трансляции раньше В, то и ее инициализация происходит раньше. Здесь есть одна на*бка особенность, которую мы увидим в примере.

3️⃣ Упорядоченная инициализация. Вот это то, что мы упоминали тут. Все переменные со static storage duration, которые не подходят под предыдущие подгруппы, инициализируются в порядке появления их определения в единице трансляции. Между разными единицами трансляции порядок инициализации не установлен.

Давайте на "простой" пример посмотрим:

struct ShowOrderHelper {
ShowOrderHelper(int num) : data{num} {
std::cout << "Object initialized with data " << num << std::endl;
}
int data;
};

static ShowOrderHelper static_var1{3};
static ShowOrderHelper static_var2{4};

struct ClassWithInlineStaticVar {
static inline ShowOrderHelper inline_member{1};
};

inline ShowOrderHelper inline_var{2};

template <class T>
struct TemplateClassWithStaticVar {
static ShowOrderHelper static_member;
};

template <class T>
ShowOrderHelper TemplateClassWithStaticVar<T>::static_member{27};


Возможный вывод:

Object initialized with data 1
Object initialized with data 2
Object initialized with data 27
Object initialized with data 3
Object initialized with data 4


Здесь как раз все три типа проявляются. static_member - статическое поле неспециализированного явно шаблона, поэтому установка ее значения в рандомном месте происходит.

Далее мы имеем уже упорядоченные вещи. inline_member определен раньше, чем inline_var, поэтому она и инициализируется раньше.

Это понятно. Но погодите: inline_member и inline_var определены позже статиков static_var1 и static_var2. Какого хера они инициализирутся раньше? Это же противоречит правилам частично упорядоченной динамической инициализации!

Вот тут-то и кроется подвох: вы наверное подумали, что из факта "если А определено раньше В, то А инициализируется раньше" автоматически вытекает, что в обратном случае А инициализируется позже. Тут вас и подловили: не вытекает. Поэтому она и называется частично упорядоченной инициализацией. В обратном случае порядок неопределен.

Теперь все понятно: inline_member инициализируется строго раньше inline_var, потому что определение стоит раньше. Но, как группа inline'ов, они расположены после static_var1 и static_var2 и в этом случае для них значение устанавливается в неизвестном порядке. В данном случае перед всеми инициализациями.

Ну и статики static_var1 и static_var2 инициализируются в ожидаемом порядке из-за применения упорядоченной инициализации.

И теперь представьте свое лицо, когда вы сделали эти переменные зависимыми друг от друга, предполагая, что статики(со static storage duration) в одной единице трансляции инициализируются в порядке появления определения. Как минимум 🗿, а как максимум🤡.

Последние несколько постов по статикам так и наровят крикнуть: "Не используйте глобальные переменные!" Ну или хотя бы старайтесь не делать их зависимыми друг от друга. Потому что с порядком полный беспорядок, а с перекрестными зависимостями остается только надеяться, что заговор бабки-поветухи на продуктивную работу поможет не словить багов.

Decouple your program. Stay cool.

#cppcore #cpp17
  • 👍 25
  • 🔥 4
  • ❤ 3
  • 😁 3
  • 🍓 2
  • 💩 1
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
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 →