marmistrz marmistrz - 1 month ago 25
C++ Question

Static order initialization fiasco, iostream and C++11

According to C++11 specification:


The results of including
<iostream>
in a translation unit shall be as if
<iostream>
defined an instance of
ios_base::Init
with static storage duration. Similarly, the entire program shall behave as if there were at least
one instance of
ios_base::Init
with static storage duration


This implies that if my code looks like that:

// A.cpp
#include <iostream>
unsigned long foo() {
cerr << "bar";
return 42;
}


and

// B.cpp

extern unsigned long foo();

namespace {
unsigned long test() {
int id = foo();
return id;
}

unsigned long id = test();
}


int main() {
return 0;
}


then I should be safe calling
cerr
without the risk of a static initialization fiasco.

Unfortunately, that code segfaults... Why? I don't think gcc 6.2.1 decided to ignore the C++11 specification, and I included
<iostream>
in A.cpp. According to the specification it should suffice.

Answer

The full quote of the paragraph includes:

The objects are constructed and the associations are established at some time prior to or during the first time an object of class ios_base::Init is constructed, and in any case before the body of main begins execution. 293)

And with the footnote

293) If it is possible for them to do so, implementations are encouraged to initialize the objects earlier than required.

So, the guarantee is that the iostreams will work at the latest when entering main. There is no strict requirement that they should work earlier, unless the translation unit includes <iostream>.

You have found a way to circumvent this!

When calling foo() from B.cpp, the ios_base::Init instance included in A.cpp may, or may not, have been initialized.