Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it ok to do printing/logging in global object constructor or it's an undefined behavior?

#include<iostream>
struct A {
  A () {
    std::cout << "A::A()\n";
  }
};
A my_a;  // works fine and prints the above line

int main () {}

According to C++ standard, order of global object initialization residing in multiple files is unspecified.
i.e. Global objects which are defined in 1 file will invoke their constructor in top to bottom order. However, if there are multiple such files, then which file will be 1st to last, is implementation defined or unspecified.

Now, std::cout and my_a both are global objects. Which means above code is a UB, is it correct (i.e. initialization fiasco)?
Possibly, the compiler might be smart enough to first initialize std objects before moving to the other ones. Still for the sake of clarity, is there any full proof way to perform logging for global objects lying across multiple files?

like image 974
iammilind Avatar asked Apr 26 '13 08:04

iammilind


1 Answers

Yes it is ok and not an UB. Usage of streams declared in iostream is clearly defined by standard.

27.4 Standard iostream objects

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. 293 The objects are not destroyed during program execution.294 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.

Thus standard requires that cout is initialized prior to first creation of ios_base::Init and #include<iostream> guarantees that it will be there. Thus by including iostream you implicitly define ios_base::Init static instance and guarantee that cout will be working correctly.

Also note 294 explicitly states that constructors and destructors of static objects are are allowed to use those objects.

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

C++03 Edit: While all quotes previously given are per C++11 and C++03 doesn't have "define ios_base::Init on iostream include" rule. C++03 still have comment about constructors and destructors of static objects under #260 instead of 294, so for C++03 it is still allowed to use cout in static object constructor.

like image 126
alexrider Avatar answered Nov 15 '22 18:11

alexrider