Насколько ленивой может быть глобальная инициализация C ++? - PullRequest
9 голосов
/ 06 августа 2009

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

Ответы [ 4 ]

6 голосов
/ 06 августа 2009

Стандарт имеет следующее в 3.6.2 / 3:

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

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

// 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.

1 голос
/ 06 августа 2009

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

0 голосов
/ 16 сентября 2013

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

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

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

0 голосов
/ 06 августа 2009

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

В 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...