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

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


ПВ>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-у.

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

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

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

Лучше избегать связи между глобальными переменными, да и их самих желательно иметь поменьше.
//в cpp файле, а не h
std::string getDefaultFoo()
{
 static const std::string Foo = "foo";
 return Foo;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.