Sign in to follow this  

Correctness of constructors before main()

This topic is 3300 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
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
If the question concerns cin and cout, then it should be safe to use them in code that would be called from code before main (global objects) - otherwise any class that uses them in the constructor (or destructor for that matter) would be technically wrong - unless you disable the possibility to create a global instance (how?). Unless perhaps you fail to include <iostream>(?)

If it concerns global objects depending on each other in general, then for example Thinking in CPlusPlus, volume 1, chapter 10 has a section on it.

But yes, avoid globals in the general case.

Share this post


Link to post
Share on other sites
Quote:
Original post by Rydinare
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.

If you're using VS then you can use init_seg. Can't remember the name for the gcc version though.

Share this post


Link to post
Share on other sites

This topic is 3300 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this