c++ - Initialize standard stream objects

前端 未结 2 783
死守一世寂寞
死守一世寂寞 2021-01-25 19:06

In what cases and why is this necessary:

class ios_base::Init {
    static int init_cnt;  // internal static counter (for exposition only)
public:
    Init();
           


        
相关标签:
2条回答
  • 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).

    0 讨论(0)
  • 2021-01-25 19:36

    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.)

    0 讨论(0)
提交回复
热议问题