Здравствуйте, Посторонним В., Вы писали:
ПВ>Есть такой код
ПВ>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;
}