Статический порядок инициализации фиаско, iostream и C++11
Согласно спецификации C++11:
Результаты в том числе
<iostream>
в переводческом блоке должно быть как<iostream>
определил экземплярios_base::Init
со статической продолжительностью хранения. Точно так же вся программа должна вести себя так, как если бы был хотя бы один экземплярios_base::Init
со статической продолжительностью хранения
Это означает, что если мой код выглядит так:
// A.cpp
#include <iostream>
using namespace std;
unsigned long foo() {
cerr << "bar";
return 42;
}
а также
// B.cpp
using namespace std;
extern unsigned long foo();
namespace {
unsigned long test() {
int id = foo();
return id;
}
unsigned long id = test();
}
int main() {
return 0;
}
тогда я должен быть в безопасности звонить cerr
без риска статического фиаско инициализации.
К сожалению, этот код segfaults... Почему? Я не думаю, что gcc 6.2.1 решил игнорировать спецификацию C++11, и я включил <iostream>
в A.cpp. Согласно спецификации, этого должно быть достаточно.
1 ответ
Полная цитата параграфа включает в себя:
Объекты создаются, и ассоциации устанавливаются за некоторое время до или в первый раз, когда создается объект класса ios_base::Init, и в любом случае до того, как тело main начинает выполнение. 293)
И со сноской
293) Если они могут это сделать, реализациям рекомендуется инициализировать объекты раньше, чем требуется.
Таким образом, гарантия заключается в том, что iostreams будут работать не позднее, чем при входе в main. Не существует строгого требования, чтобы они работали раньше, если блок перевода не включает <iostream>
,
Вы нашли способ обойти это!
При звонке foo()
из B.cpp, ios_base::Init
экземпляр, включенный в A.cpp, может или не может быть инициализирован.