Инициализация статических полей класса. Ч3



В первой части мы разобрали порядок инициализации статических поле в случае их out-of-class определения. Однако в современных плюсах редко, кто вне описания класса инициализирует статические поля. Все потому что в С++17 появились инлайн переменные, которые позволяют не нарушать ODR при наличии их определения в разных единицах трансляции. Подробнее об этом тут. Эта фича позволила определять статические поля сразу внутри описания класса. Более подробно об этом тут.



Ну и встает вопрос: в каком порядке инициализируются inline static class members?



В целом, ответ такой же: в порядке определения. Только эти определения теперь совмещены с объявлением, поэтому можно сказать, что инициализация происходит в порядке появления этих полей в описании класса. Спасибо Артему Кузнецову, что указал в комментариях на эту особенность)



Ну и для того, чтобы пост был не таким скучным, давайте попробуем смешать обычные статические мемберы и инлайновые и посмотрим, как эта смесь будет себя вести.



Выглядит это примерно так:



struct Helper {

Helper(int num) : data{num} {

std::cout << "Helper " << num << std::endl;

}

private:

int data;

};



struct Class {

static inline Helper a{1};

static Helper b;

static inline Helper c{2};

};



Helper Class::b{3};



int main() {}





Вывод будет таким:



Helper 1

Helper 2

Helper 3





В целом, картина довольно понятная. Если линкер ставит инициализацию статиков по порядку их определения, то здесь прослеживается та же история. Первыми инициализируются инлайны по порядку появления их в классе, а последним инициализируется неинлайновое поле, даже с учетом того, что оно объявлено между двумя первыми.



Так что порядок следования определений - наше все.



Rely on explicitly stated rules. Stay cool.



#cpp17 #cppcore