Is Std::Cout Guaranteed to Be Initialized

Is std::cout guaranteed to be initialized?

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.

Considering that std::cout is an initialized object, why does visual studio 'not recognise its identifier' whilst setting a Watch in the debugger?

you could create a local reference to std::cout and add a watch for that. E.g.:

auto& mycout = std::cout;

How is `std::cout` implemented?


how std::cout is created?

First things first, from https://en.cppreference.com/w/cpp/io/ios_base/Init :

std::ios_base::Init

This class is used to ensure that the default C++ streams (std::cin,
std::cout, etc.) are properly initialized and destructed. [...]

The header <iostream> behaves as if it defines (directly or
indirectly) an instance of std::ios_base::Init with static storage
duration: [...]

Meh, let's do a real code example. I will be using GCC C++ library. From https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/iostream#L73 , this is the important part:

 // For construction of filebuffers for cout, cin, cerr, clog et. al.
static ios_base::Init __ioinit;

Now we jump to the constructor of ios_base::Init class, in https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc#L85 :

ios_base::Init::Init()
{
if (__gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 1) == 0)
{
// Standard streams default to synced with "C" operations.
_S_synced_with_stdio = true;

new (&buf_cout_sync) stdio_sync_filebuf<char>(stdout);
new (&buf_cin_sync) stdio_sync_filebuf<char>(stdin);
new (&buf_cerr_sync) stdio_sync_filebuf<char>(stderr);

// The standard streams are constructed once only and never
// destroyed.
new (&cout) ostream(&buf_cout_sync);
new (&cin) istream(&buf_cin_sync);
new (&cerr) ostream(&buf_cerr_sync);
new (&clog) ostream(&buf_cerr_sync);
cin.tie(&cout);
cerr.setf(ios_base::unitbuf);
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 455. cerr::tie() and wcerr::tie() are overspecified.
cerr.tie(&cout);

The _S_refcount is there for when you would call ios_base::Init::Init(); manually from a constructor of a static class, it protects against double initialization.

The stdio_sync_filebuf is an internal buffer for istream/ostream and it is meant to handle cstdio FILE* operations to get/put input/output data, with implementation here https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/ext/stdio_sync_filebuf.h#L56 . It inherits from std::basic_streambuf.

So cout is constructed in-place with stdio_sync_filebuf<char> as parameter. It is the first constructor mentioned here https://en.cppreference.com/w/cpp/io/basic_ostream/basic_ostream .

Now, because the stuff is constructed in-place, you might wonder how is the memory allocated? From https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/globals_io.cc#L50 :

  // Standard stream objects.
// NB: Iff <iostream> is included, these definitions become wonky.
typedef char fake_istream[sizeof(istream)]
__attribute__ ((aligned(__alignof__(istream))));
typedef char fake_ostream[sizeof(ostream)]
__attribute__ ((aligned(__alignof__(ostream))));
fake_istream cin;
fake_ostream cout;
fake_ostream cerr;
fake_ostream clog;

The objects are just empty char buffers of proper size and proper alignment.

And yes, you can construct ostream yourself, with __gnu_cxx::stdio_sync_filebuf on GCC:

#include <fstream>
#include <ext/stdio_sync_filebuf.h>
int main() {
__gnu_cxx::stdio_sync_filebuf<char> mybuf_cout_sync(stdout);
std::ostream os(&mybuf_cout_sync);
os << "Hello world!\n";
return 0;
}

Or, to be portable, you would write your own class that inherits from std::streambuf and construct ostream from it yourself. There are many examples online, like for example here https://stackoverflow.com/a/51250032/9072753 .

Where is std::cout defined?

How libstdc++ used by gcc does it:

Storage for cout is defined as a global variable of type fake_ostream which is presumably constructible without problems.
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/globals_io.cc

Then during library initialization rewritten with a placement new using the explicit constructor.
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc

Other compilers have their own libraries and may use different tricks. Examining the source of libc++ used by clang left as exercise for the reader.

Is cout guaranteed available during static deinitialization?

Short Answer: Yes

Long Answer: Yes

There are a couple of tricks that the standard library uses to make sure that std::cout (and std::cin/std:cerr) are available before any other objects (But you must #include <iostream> in the translation unit). Because they are created first (the reverse order of destruction rule guarantees) they are destroyed after your objects.

See: n3242 (Practically the C++0x standard Pub: 2011-02-28)

27.4 Standard iostream objects

Paragraph 2

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. The objects are not destroyed during program execution. The results of including 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.

Added highlighting.

From n1804 (which is basically the 2003 standard: Pub: 2005-04-27)

27.3 Standard iostream objects

Paragraph 2

Mixing operations on corresponding wide- and narrow-character streams follows the same semantics as mixing such operations on FILEs, as specified in Amendment 1 of the ISO C standard. The objects 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. The objects are not destroyed during program execution280.

Unfortunately the bit that would make it a guarantee is in the footnotes (which are non-normative (ie its not guaranteed just what the implementer should try and achieve).

With the footnotes:

280) Constructors and destructors for static objects can access these objects to read input from stdin or write output to stdout or stderr.

Is it guaranteed by the C++ standard that cin, cout, etc. will be created first and destroyed last?

They are guaranteed to be created before any static object declared after including <iostream> and, in any case, before starting main. They are not destroyed during program execution.

Including the header has the effect of declaring a static variable of type ios_base::Init, whose creation ensures that the standard streams are initialised.

If you want the Standardese for this:

C++11 27.4.1 [iostream.objects.overview]/2: 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. The objects are not destroyed during program execution. 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.

Order of initialization

An example would be cout.

The compiler doesn't really guarantee that those objects are built before they are used. Take this code:

struct Foo
{

Foo();
}foo;

#include <iostream>

Foo::Foo()
{
std::cout << "Hello World";
}

int main() {}

It segfaults because the foo object gets built before cout. When it tries to use cout, bad things happen.

Basically, all the global objects will get code inserted to construct them which runs before main. Once you are in main you are safe, all objects are built. Before that it depends on the order in which they are defined. That's why I can break it by including iostream after declaring the foo global.

About std::cout, why use extern rether than singleton pattern

Using an extern variable allows the (subjectively) nicer syntax of

std::cout << stuff;

Emphasizing that the standard stream is a unique object and not the result of some function call. Since streaming is meant to be done into stream objects, using object notation ties better into it.

As for the static initialization order fiasco, the standard library avoids it by using the Schwarz Counter technique for initialization. Initialization happens in a well defined order because including iostream adds a special global object of type Init to the including TU. The object's constructor handles the initialization of the stream before its first use, wherever that first use may be.

Variable templates and std::cout -- order of construction

As explained in that question, one effect of

#include <iostream>

is the equivalent of defining a global variable

static std::ios_base::Init __init;

which (assuming that you include it at the start of the TU) guarantees that for all static storage duration objects with ordered initialization in the same TU, the stream objects have been set up.

However, explicitly and implicitly instantiated template specializations have unordered initialization ([basic.start.dynamic]/1)1:

Dynamic initialization of a non-local variable with static storage
duration is unordered if the variable is an implicitly or explicitly
instantiated specialization, and otherwise is ordered [note omitted]. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.

And since

If a program starts a thread, the subsequent unordered initialization
of a variable is unsequenced with respect to every other dynamic
initialization. Otherwise, the unordered initialization of a variable
is indeterminately sequenced with respect to every other dynamic
initialization.

there's no guarantee that the stream objects have been initialized at the time the variable template specialization x<Test> is initialized.

In this case, as one of the possible executions results in undefined behavior (using the stream objects before they are initialized), the behavior of the entire program is undefined (see [intro.execution]/5).

The fix is to construct a std::ios_base::Init object yourself in Test's constructor.


1 This is actually underspecified for variable templates when C++14 was published, but it's always been the intent.



Related Topics



Leave a reply



Submit