2013-10-27 8 views
8

У меня есть кусок кода структурированную, как это:Когда создаются глобальные переменные?

a.cpp: 
    #include "b.hpp" 
    const unsigned a = create(1); 


b.cpp: 
    map<int, string> something; // global variable 
    unsigned create(unsigned a){ 
     something.insert(make_pair(a, "somestring")); 
     return a; 
    } 

Теперь это выбрасывает Segfault, Valgrind говорит, что карта еще не была создана. Как это работает, как мне его изменить?

ответ

10

C++ не определяет порядок, когда глобальные переменные создаются во время запуска программы. a может быть инициализирован сначала до того, как будет построено something, что вызовет проблему выше. Когда вы начинаете строить глобальные переменные, которые зависят от инициализации других глобальных переменных, вы запускаете классический фиаско порядка инициализации .

Простой способ исправить описанный выше сценарий - сделать something статическим и переместить его в функцию create.

unsigned create(unsigned a) 
{ 
    static map<int, string> something; 
    something.insert(make_pair(a, "somestring")); 
    return a; 
} 

Это будет гарантировать something получает создан на первом вызове create.

3

Порядок, в котором глобальные переменные из разных единиц перевода (т. Е. Расположенных в разных * .cpp-файлах) инициализируются, не определяется стандартом. Таким образом, полагаясь на это, undefined behaviour. Смотрите также:

8

Все глобальные переменные создаются перед входом в основной(), но их порядок строительства между различными единицами перевода не указан в C Стандарт ++. Их порядок построения в пределах одной единицы перевода соответствует порядку спецификации.

Вы можете создать что-то, что гарантируется стандартом. Что-то вроде этого:

map<int, string>& mymap(){ 
    static map<int, string> something; 
    return something; 
} 

unsigned create(unsigned a) { 
    mymap().insert(make_pair(a, "somestring")); 
    return a; 
} 

Карта что-то создается при первом вызове функции mymap().

+2

Глобальные переменные внутри каждой единицы трансляции строятся в порядке их декларации. Порядок ** между ** единицами перевода, действительно, не указан. –

+1

Их даже не нужно «строить» (динамически инициализировать) перед вводом 'main', см. [Basic.start.init]/4.Чтобы добавить дополнительное усложнение, элемент статических данных не явно специализированных шаблонов классов имеет неупорядоченную инициализацию, все остальное имеет упорядоченную инициализацию (внутри TU). – dyp

2

Порядок, в котором глобальные переменные (то есть переменные в области видимости пространства имен) создается указано в существе:

  • порядок, в котором они появляются в единице трансляции
  • не определено, от одного единица перевода в другую

Это то, что языки с модулями не страдают, но, к сожалению, общая проблема на C++. Используя функции-локальные статические переменные, можно получить инициализацию при первом использовании, что обычно решает эту проблему.

Пример статического локального:

int func(int a) { 
    static std::map<int, int> m; 
    return m[a] = m.size(); 
} 
+1

«порядок, в котором они отображаются, в единицах перевода», если они не являются статическими элементами данных не явно специализированных шаблонов классов (для динамической инициализации). – dyp

Смежные вопросы