Насколько ленивой может быть глобальная инициализация C++?

StackOverflow https://stackoverflow.com/questions/1239235

Вопрос

Я привык думать, что вся инициализация глобальных переменных/членов статического класса происходит до первой строки main().Но недавно я где -то читал, что стандарт позволяет инициализации позже, чтобы «помочь с динамической загрузкой модулей». Я мог видеть, что это правда, когда динамическое связывание:Я бы не ожидал, что глобальная инициализация в библиотеке будет инициализирована до того, как я открою библиотеку.Однако в группе статически связанных друг с другом единиц перевода (прямых файлов .o моего приложения) такое поведение показалось бы мне очень неинтуитивным.Это происходит только лениво при динамическом связывании или может произойти в любое время?(или я неправильно прочитал?;)

Это было полезно?

Решение

В стандарте 3.6.2/3 есть следующее:

Реализация определяется независимо от того, осуществляется ли динамическая инициализация (8.5, 9.4, 12.1, 12.6.1) объекта сфера пространства имен выполняется перед первым утверждением Main.Если инициализация откладывается до какой -то точки времени после первого оператора Main, она должна произойти до первого использования любой функции или объекта, определенного в той же блоке перевода, что и инициализированное объект.

Но о Конечно вы можете никогда официально сообщить, когда произойдет инициализация поскольку инициализация произойдет до того, как вы получите доступ к переменной! следующее:

// t1.cc
#include <iostream>
int i1 = 0;

int main () {
  std::cout << i1 << std::endl

// t2.cc
extern int i1;
int i2 = ++i1;

Я могу подтвердить, что g++ 4.2.4, по крайней мере, выполняет инициализацию «i2» перед main.

Другие советы

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

Давайте рассмотрим псевдокод:

В DLL:

static int ItsDllVar = 1;
int EXPORTED_FUNCTION() { return ItsDllVar; }

В приложении:

static int AppVar1 = 2;
static int AppVar2 = EXPORTED_FUNCTION() + AppVar1;

Таким образом, согласно статической инициализации AppVar2 получает 1+2=3.

Ленивая инициализация, применимая для локальных статических переменных (независимо от DLL).

int f()
{
    static int local_i = 5;//it get's 5 only after visiting f()
    return local_i;
}

Я думаю, именно это произошло в моем случае с g++ 4.7 и CMake (не уверен, что это важная деталь, касающаяся CMake).У меня есть код, который регистрирует функцию на фабрике.Он основан на вызове конструктора из глобально инициализированной переменной.

Когда этот код был в статически связанная библиотека инициализация не произошла!Теперь он работает нормально, когда я переместил его в объектные файлы, которые связаны напрямую (т. е. они не объединяются сначала в библиотеку).

Так что я подозреваю, что вы правы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top