Is std::cout guaranteed to be initialized?
Asked Answered
H

3

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?

Hartmann answered 9/1, 2012 at 6:59 Comment(3)
Related to #6920093 which also covers construction in the answer.Sullage
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.Australopithecus
PS. Also note the order of destruction is guaranteed (the inverse of construction).Australopithecus
P
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.

Post answered 9/1, 2012 at 7:11 Comment(1)
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.Australopithecus
P
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.

Petitionary answered 9/1, 2012 at 7:3 Comment(7)
Which says nothing about the order of construction of std::cout relative to other static objects.Owades
@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.Malformation
@BasileStarynkevitch: It actually does. The paragraph continues: "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." 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 <iostream> before you declare your variables, which I sincerely hope)Shortchange
@knatten: And what if you include other headers before <iostream> which declare static variables?Boar
@MatthieuM.: If they use cout, they would have to include <iostream> themselves anyway.Shortchange
@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 <iostream>), in which case the header does not need to include <iostream> itself.Boar
@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.Shortchange
O
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.

Owades answered 9/1, 2012 at 7:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.