Re[2]: Порядок инициализации статических переменных
От: HolyNick  
Дата: 11.12.13 10:50
Оценка:
Здравствуйте, HolyNick, Вы писали:

HN>Здравствуйте, Посторонним В., Вы писали:


ПВ>>Есть такой код


ПВ>>a.h

ПВ>>
ПВ>>...
ПВ>>namespace X
ПВ>>{
ПВ>>    const std::string Foo = "foo";
ПВ>>    inline std::string getFoo()
ПВ>>    {
ПВ>>        return Foo;
ПВ>>    }
ПВ>>}
ПВ>>...
ПВ>>


ПВ>>a.cpp:

ПВ>>
ПВ>>#include "a.h"
ПВ>>...
ПВ>>namespace X
ПВ>>{
ПВ>>   const string Default_Foo = getFoo();
ПВ>>}
ПВ>>...
ПВ>>


ПВ>>Само-собой в проекте есть еще файлы, который инклудят a.h


ПВ>>На старте программа валится в segfault в выделенной строчке. Исследование показало, что:


ПВ>>1. в программе создается несколько копий Foo

ПВ>>
ПВ>>-bash-4.2# nm -oC a.out | grep Foo
ПВ>>/usr/local/bin/RESEPT/www/authmod.fcgi:3c162c50 b X::Foo
ПВ>>/usr/local/bin/RESEPT/www/authmod.fcgi:3c162990 b X::Foo
ПВ>>/usr/local/bin/RESEPT/www/authmod.fcgi:3c1641b0 b X::Foo
ПВ>>


ПВ>>2. В процессе инициализации Default_Foo вызывается getFoo(), которая берет не уже инициализированую Foo из единицы компиляции a.cpp (как я бы ожидал), а Foo из другой единицы компиляции, в которой, волею судеб, Foo еще не инициализирована.

ПВ>>Что приводит в segfault-у.

ПВ>>Кто-нибудь может объяснить, верно ли такое поведение?

ПВ>>Как лучше всего избегать такого рода ошибок?

HN>Глобальные\статические переменные определенные в одной единице трансляции скорее всего будут создаваться\инициализироваться в порядке их определения. Порядок инициализации

HN>глобальных\статических переменных в разных единицах трансляции определяется порядком их(сpp файлов) обработки линковщиком, те для программиста заранее неизвестен в общем-то.

HN>Лучше избегать связи между глобальными переменными, да и их самих желательно иметь поменьше.

HN>
HN>//в cpp файле, а не h
HN>std::string getDefaultFoo()
HN>{
HN> static const std::string Foo = "foo";
HN> return Foo;
HN>}
HN>


PS: Обработка линковщиком конечно же объектных файлов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.