44

What I know about C++ is that the order of the constructions (and destructions) of global instances should not be assumed.

While I'm writing code with a global instance which uses std::cout in the constructor & destructor, I got a question.

std::cout is also a global instance of iostream. Is std::cout guaranteed to be initialized before any other global instances?

I wrote a simple test code and it works perfectly, but still I don't know why.

#include <iostream>

struct test
{
    test() { std::cout << "test::ctor" << std::endl; }
    ~test() { std::cout << "test::dtor" << std::endl; }
};

test t;

int main()
{
    std::cout << "Hello world" << std::endl;
    return 0;
}

It prints

test::ctor
Hello world
test::dtor

Is there any possibility that the code doesn't run as expected?

Destructor
  • 14,123
  • 11
  • 61
  • 126
Inbae Jeong
  • 4,053
  • 25
  • 38
  • 1
    Related to http://stackoverflow.com/questions/6919593/is-cout-guaranteed-available-during-static-deinitialization which also covers construction in the answer. – adl Jan 09 '12 at 07:11
  • The initialization order of static storage duration objects at the global scope can not be assumed but there are tricks to force the initialization order. – Martin York Jan 09 '12 at 10:04
  • PS. Also note the order of destruction is guaranteed (the inverse of construction). – Martin York Jan 09 '12 at 10:11

3 Answers3

45

The answer differs depending on if you're using C++03 or C++11.

In C++11, your code is guaranteed to work, but in C++03 it's unspecified; your only guarantee is that by the time main() is entered, the standard streams had been initialized. (That said, all mainstream implementations initialize them prior to running any dynamic initialization, making them fine to use.)

You can force initialization by constructing an std::ios_base::Init object, like so:

#include <iostream>

struct test
{
    test() { std::cout << "test::ctor" << std::endl; }
    ~test() { std::cout << "test::dtor" << std::endl; }

private:
    std::ios_base::Init mInitializer;
};

test t;

int main()
{
    std::cout << "Hello world" << std::endl;
    return 0;
}

Now when test constructs, it initializes mInitializer and guarantees the streams are ready to use.

C++11 fixed this slightly annoying behavior by acting as if every instance of #include <iostream> were followed by static std::ios_base::Init __unspecified_name__;. This automatically guarantees the streams are ready to use.

Léo Lam
  • 3,870
  • 4
  • 34
  • 44
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 2
    In C++03 the obvious intent (as indicated by the foot note) is to guarantee that std::cin/std::cout objects are fully constructed before other objects. – Martin York Jan 09 '12 at 10:08
12

According to §27.3/2:

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

Tacet
  • 1,411
  • 2
  • 17
  • 32
Guillaume Paris
  • 10,303
  • 14
  • 70
  • 145
  • 2
    Which says nothing about the order of construction of `std::cout` relative to other static objects. – Basile Starynkevitch Jan 09 '12 at 07:06
  • 13
    @BasileStarynkevitch: Sort of true, but footnote 265 (referenced from §27.3/2) says it should work: "Constructors and destructors for static objects can access these objects to read input from stdin or write output to stdout or stderr." That may not be normative, but clearly states at least the *intent* that his code should work. – Jerry Coffin Jan 09 '12 at 07:09
  • 4
    @BasileStarynkevitch: It actually does. The paragraph continues: "The results of including in a translation unit shall be as if defined an instance of ios_base::Init with static storage duration." And since static non-local variables in the same translation unit are initialized in the order of declaration, `cout` is guaranteed to have been initialized before your other non-local statics. (Assuming you `#include ` before you declare your variables, which I sincerely hope) – knatten May 12 '13 at 16:30
  • 1
    @knatten: And what if you include other headers before `` which declare static variables? – Matthieu M. Feb 04 '16 at 13:42
  • @MatthieuM.: If they use `cout`, they would have to `include ` themselves anyway. – knatten Feb 05 '16 at 15:51
  • @knatten: you are forgetting the separate compilation model, just because a header creates a static/global variable does not mean the constructor of said variable is inlined in the header! It can be tucked in a cpp file (and this one includes ``), in which case the header does not need to include `` itself. – Matthieu M. Feb 06 '16 at 11:35
  • 2
    @MatthieuM. I agree, but that was not my point either. The standard does indeed not specify when `cout` is initialised. It only specifies that for a particular translation unit, the result is *as if* an instance was defined in that header. This is just a standardese way to guarantee that it is safe to use `cout` even in static objects. – knatten Feb 08 '16 at 19:12
2

Your question is about the order of construction of static objects. I believe that the language specification leaves it undefined.

GCC has the init_priority attribute to play with the order.

And I believe you should not worry that much in practice.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547