Статический порядок инициализации фиаско, 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, может или не может быть инициализирован.

Другие вопросы по тегам