Динамическая инициализация
После статической инициализации в компайлтайме идет динамическая инициализация в рантайме. Хотелось бы сказать, что хоть здесь простой и понятный порядок, но нет. Это глобальные переменные и С++, поэтому будет немного больно.
Динамическая инициализация разделяется на 3 подгруппы:
1️⃣ Неупорядоченная динамическая инициализация. Она применяется только для статических полей шаблонных классов и шаблонных переменных, которые не специализированы явно(явно специализированные шаблоны - обычные классы). И вот порядок установки значений этих сущностей вообще неопределен. Куда понравится компилятору, туда и вставит.
2️⃣ Частично упорядоченная инициализация. Применяется для всех нешаблонных инлайн переменных. Есть 2 переменные: inline переменная А и В, которая не подходит под критерии применения первой подгруппы. Если А определена во всех единицах трансляции раньше В, то и ее инициализация происходит раньше. Здесь есть однана*бка особенность, которую мы увидим в примере.
3️⃣ Упорядоченная инициализация. Вот это то, что мы упоминали тут. Все переменные со static storage duration, которые не подходят под предыдущие подгруппы, инициализируются в порядке появления их определения в единице трансляции. Между разными единицами трансляции порядок инициализации не установлен.
Давайте на "простой" пример посмотрим:
Возможный вывод:
Здесь как раз все три типа проявляются.
Далее мы имеем уже упорядоченные вещи.
Это понятно. Но погодите:
Вот тут-то и кроется подвох: вы наверное подумали, что из факта "если А определено раньше В, то А инициализируется раньше" автоматически вытекает, что в обратном случае А инициализируется позже. Тут вас и подловили: не вытекает. Поэтому она и называется частично упорядоченной инициализацией. В обратном случае порядок неопределен.
Теперь все понятно:
Ну и статики
И теперь представьте свое лицо, когда вы сделали эти переменные зависимыми друг от друга, предполагая, что статики(со static storage duration) в одной единице трансляции инициализируются в порядке появления определения. Как минимум 🗿, а как максимум🤡.
Последние несколько постов по статикам так и наровят крикнуть: "Не используйте глобальные переменные!" Ну или хотя бы старайтесь не делать их зависимыми друг от друга. Потому что с порядком полный беспорядок, а с перекрестными зависимостями остается только надеяться, что заговор бабки-поветухи на продуктивную работу поможет не словить багов.
Decouple your program. Stay cool.
#cppcore #cpp17
После статической инициализации в компайлтайме идет динамическая инициализация в рантайме. Хотелось бы сказать, что хоть здесь простой и понятный порядок, но нет. Это глобальные переменные и С++, поэтому будет немного больно.
Динамическая инициализация разделяется на 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