Thread: order of initialization and cout

  1. #1
    Registered User
    Join Date
    Jan 2007
    Posts
    330

    order of initialization and cout

    Does the following code produce undefined behaviour?

    Code:
    #include <iostream>
    
    class X
    {
    public:
      X() { std::cout << "X" << std::endl;
    };
    
    static X x;
    
    int main()
    {
      X x2;
    
      return 0;
    }
    Im talking specifically about the the constructor of X which uses std::cout. cout and "static X x" are both global objects and class X uses cout in its constructor before main is entered. In other words, can I always depend on cout being constructed properly before use?

  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Yes.

    It will not work for your own classes, but `std::cout' is a guaranteed entity.

    Soma

  3. #3
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Edit: Nevermind. Misread the question.

    So, here it it. Correctly now:

    It will not work for your own classes,
    It can. For instance,

    test.hpp
    Code:
    class foo {
    
    public:
        foo(): val_(12) {}
        int getval() { return val_; }
    
    private:
        int val_;
    
    };
    
    static foo bar;
    main.cpp
    Code:
    #include <iostream>
    #include "test.hpp"
    
    class X {
    
    public:
    	X() { value_ = bar.getval(); }
    	int getvalue() { return value_; }
    
    private:
    	int value_;
    
    };
    
    static X x;
    
    int main() {
    
    
      X x2;
      std::cout << x.getvalue();
    
      return 0;
    
    }
    Last edited by Mario F.; 09-03-2009 at 05:11 AM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Of course it can, but it isn't guaranteed that bar is properly constructed before x. Therefore, it's undefined behavior and bad to rely on.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Why not? Isn't the order defined within the same compilation unit?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Is it? I'm under the impression it is not.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by Elysia View Post
    I'm under the impression it is not.
    Only across different compilation units. And even so you can control it through things like (according to the previous example):

    hide.hpp
    Code:
    class foo {
    
    public:
        foo(): val_(12) {}
        int getval() { return val_; }
    
    private:
        int val_;
    
    };
    test.cpp
    Code:
    #include "hide.hpp"
    foo& getfoo() {
    
        static foo bar;
        return bar;
    
    }
    test.hpp
    Code:
    #include "hide.hpp"
    foo& getfoo();
    You then use test.hpp as your header file in main. This simple method guarantees you control over initialization order across different compilation units.

    ...

    As for cout, this is simple because the C++ standard requires that cout, cin, cerr and its wide brothers and sisters be defined prior to any other user-defined objects. How it exactly goes about this, I'm unsure. Probably by having them already pre-compiled?

    In any case, because of this you can even use cout and family on the destructors of your static objects on any compilation unit.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Ah, I see. Initialization is top to bottom in compilation units then? Or something else entirely?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Well, I never liked the analogy because it forgets to mention objects that may be being defined by other objects.

    In any case, yes. Top to bottom, not moving forward until all types on a given branch have been defined.
    Last edited by Mario F.; 09-03-2009 at 06:57 AM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  10. #10
    The larch
    Join Date
    May 2006
    Posts
    3,573
    As for cout, this is simple because the C++ standard requires that cout, cin, cerr and its wide brothers and sisters be defined prior to any other user-defined objects. How it exactly goes about this, I'm unsure. Probably by having them already pre-compiled?
    MinGW's <iostream> header has these lines:

    Code:
      // For construction of filebuffers for cout, cin, cerr, clog et. al.
      static ios_base::Init __ioinit;
    That is, the construction of this object somehow forces the constructors for streams to be called.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  11. #11
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    It will not work for your own classes. You can't pretend otherwise by limiting yourself to a single translation unit or using the "accessor trick".

    Soma

  12. #12
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by phantomotap View Post
    It will not work for your own classes. You can't pretend otherwise by limiting yourself to a single translation unit or using the "accessor trick".
    "accessor cheat". Cheat is more appropriate I guess, since what it is doing is giving the impression of a global object when in fact it is a local object.(*)

    It's quite irrelevant what you think on this matter, I'm afraid. All that it is being asked is how can I guarantee order of initialization of a static global object. Since I cannot tell the compiler to do something its patriotic allegiance to the standards forbids him of doing, the alternative is to offer sideways solutions.

    Solutions that work. Solutions that, contrary to what your assertion seems to want to indicate, are used successfully and handle the problem on a daily basis. This is the realm of problem solving. And you can't solve a problem without compromising. Especially in your adherence to strict semantics.

    (*) incidentally this is pretty much the makings of a singleton object. So one might want to take the next step and actually fully apply the pattern to the object, in doing so offering a more elegant and reusable solution.
    Last edited by Mario F.; 09-03-2009 at 12:27 PM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  13. #13
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    >> "accessor cheat". Cheat is more appropriate I guess...
    I was always under the impression this was known as the "construct on first use" idiom. I wouldn't call it a trick or a cheat; I think idiom suits it nicely.
    bit∙hub [bit-huhb] n. A source and destination for information.

  14. #14
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Ah, thanks bithub. I was struggling to remember the proper name. It was driving me nuts particularly on this last post when it seemed to me would be more proper.

    Long time away from the books and a preliminary search on google didn't reveal me any hints.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  15. #15
    The larch
    Join Date
    May 2006
    Posts
    3,573
    It will not work for your own classes, but `std::cout' is a guaranteed entity.
    Why will it (what?) not work for your own classes. The standard seems to prescribe in detail how it should be implemented for cout etc and it seems that the implementation uses only normal language rules. For example, GCC's comment on ios_base::Init:

    Code:
        // 27.4.2.1.6  Class ios_base::Init
        // Used to initialize standard streams. In theory, g++ could use
        // -finit-priority to order this stuff correctly without going
        // through these machinations.
    I also seem to remember an article that demonstrates a better way which hadn't been discovered by the time iostreams were invented.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 02-28-2008, 11:51 PM
  2. member variable initialization
    By George2 in forum C++ Programming
    Replies: 6
    Last Post: 12-29-2007, 09:52 AM
  3. Data member initialization
    By Fyodorox in forum C++ Programming
    Replies: 4
    Last Post: 04-29-2002, 11:09 PM
  4. Variable Declaration & Initialization :: C++
    By kuphryn in forum C++ Programming
    Replies: 6
    Last Post: 12-26-2001, 10:22 AM
  5. Replies: 2
    Last Post: 12-25-2001, 04:18 PM