In what cases and why is this necessary:
class ios_base::Init {
static int init_cnt; // internal static counter (for exposition only)
public:
Init();
They're needed to ensure the correct initialization of the
standard iostream objects, like std::cout
. Basically, the
standard iostream objects are guaranteed to be constructed by
the time the first constructor of ios_base::Init
has finished.
(The init_cnt
member is part of one technique of achieving
this.) In addition, the standard says that including
<iostream>
declares a static instance of ios_base::Init
(or
behaves as if it does), so if you write:
#include <iostream>
class X
{
public:
X() { std::cout << "something";
};
X anXwithStaticLifetime;
you're guaranteed that std::cout
will be constructed before
the constructor of anXwithStaticLifetime
is run.
Of course, this only works within a single translation unit. If you define in a header ("X.hh"):
class X
{
public:
X();
};
and then in two different translation units:
#include "X.hh"
#include <iostream>
X::X()
{
std::cout << "something";
}
and:
#include "X.hh"
X anXwithStaticLifetime;
it's quite possible that std::cout
will not have been
constructed when you execute the constructor. The usual way of
ensuring this is to define a local instance of ios_base::Init
in the constructor:
X::X()
{
static ios_base::Init toEnsureInitialization;
std::cout << "something";
}
In practice, most implementations use additional tricks to reduce the risk. But as far as I know, none of them are 100%, and depending on how you link, you can still get into problems. But they won't occur if you do things the usual way. With the results that a lot of programmers aren't aware of the risk, and don't make the necessary declaration (and it almost always works anyway).
It's a workaround for the static initialization order fiasco. Essentially, if you want to use the global stream objects from a static initializer, you can call this to ensure that they're all constructed in time. Runtimes I'm familiar with already do this properly, but technically speaking that's not guaranteed.
(Note also that as of C++11, it is guaranteed.)