Jump to content
  • Advertisement
Sign in to follow this  
spraff

Correctness of constructors before main()

This topic is 3513 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi there. In C++, it's possible to statically declare objects whose constructors get called before main(), std::cin and std::cout for example. Trouble for me is, this doesn't work across objects which aren't defined in the same file. For example, the following is unsafe
Foo::Foo() {
    std::cout << "Hi\n";
}
Foo foo;
Foo bar;

int main () {
    return 0;
}

This will work only if the linker happens to decide that std::cout's constructor is called before foo's or bar's. AFAIK, this behaviour is undefined (although we can guarantee that foo will be constructed before bar). This is causing me problems because I'm hiding initialisation code in anonymous constructors like this. It's elegant when it works. I don't expect it to be possible to guarantee the order of construction outside of main() (in fact, I can think of good reasons not to allow that), but can anyone tell me if guarantees can be made for the initial values of built-in types? If you have
const char * text = "Hello.";
int main() {

there isnt a constructor for "text" which copies in "Hello" from elsewhere, it's part of the compiled binary and loaded into memory before the program starts, right? Can I be sure that if instead of creating "Foo foo;" outside of main() and finding it undefined, I can write "Foo*foo=0;" and that will definitely be assigned its value before any of my extramain constructors are called? Thank you and good night.

Share this post


Link to post
Share on other sites
Advertisement
The solution I would suggest is to avoid global objects as much as possible. I know the standard did it, but if it could be redone, I bet it would be done differently.

Particularly what you need to avoid is if you have a global object whose constructor or destructor depends on another global object. If you start doing this, seriously, it's time for redesign.

In your case, just put Foo foo, and Bar bar in main and pass it along to other functions which use them.

Share this post


Link to post
Share on other sites
If you want to guarantee that std::cout will be initialized before creating your Foo objects, you can create a std::basic_ios<char>::Init object in your source file before the Foo objects are created. Ex:

std::basic_ios<char>::Init init;
Foo foo;
Foo bar;

Objects with static storage duration are guaranteed to be zero initialized before all other initialization happens.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Objects with static storage duration are guaranteed to be zero initialized before all other initialization happens.


Really? What about my const char * text = "Hello" example? When does that cease to be zero?

Share this post


Link to post
Share on other sites
However, the comment in MingW's iostream header says:

Quote:

/**
* @name Standard Stream Objects
*
* The <iostream> header declares the eight standard stream
* objects
. For other declarations, see
* http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#10 and the
* @link s27_2_iosfwd I/O forward declarations @endlink
*
* They are required by default to cooperate with the global C library's
* @c FILE streams, and to be available during program startup and
* termination. For more information, see the HOWTO linked to above.
*/


This suggests that there are techniques to guarantee something global is available before other things, and that the implementations are required to employ them so that it is safe to use cout as you do.

In particular, the header already contains what SiCrane suggested to use.

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
However, the comment in MingW's iostream header says:

Quote:

/**
* @name Standard Stream Objects
*
* The <iostream> header declares the eight standard stream
* objects
. For other declarations, see
* http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#10 and the
* @link s27_2_iosfwd I/O forward declarations @endlink
*
* They are required by default to cooperate with the global C library's
* @c FILE streams, and to be available during program startup and
* termination. For more information, see the HOWTO linked to above.
*/


This suggests that there are techniques to guarantee something global is available before other things, and that the implementations are required to employ them so that it is safe to use cout as you do.


It's possible there are non-standard mechanisms, but I'm not aware of any standard ones. In general, I would avoid the non-standard mechanism, since there's a better workaround anyway.

Share this post


Link to post
Share on other sites
If the standard requires that cout and cin are available to be used at program start-up what does it matter if the compiler writers use a non-standard technique to achieve this?

In particular the <iostream> header contains the following line, just as SiCrane suggested:

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


As <iostream> will be included before your code it will work.

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
If the standard requires that cout and cin are available to be used at program start-up what does it matter if the compiler writers use a non-standard technique to achieve this?

In particular the <iostream> header contains the following line, just as SiCrane suggested:

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


As <iostream> will be included before your code it will work.


I definitely remember seeing it fail before, but that definitely was years ago and I no longer remember the circumstances. Perhaps it's what you're saying, that iostream wasn't included first, which caused the problem. Even so, why not just avoid the hassle by avoiding globals? [smile]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!