In C ++, is this a good form for writing code that runs before main ()?

Constructors of world-declared classes are called before main is entered. Although this can be confusing for a new code reader because it is not often done, is this necessarily a bad idea?

+7
c ++ constructor
source share
7 answers

This is not necessarily a bad idea, but usually yes.

The first is global data, and global values ​​are usually bad. The more global you have, the more difficult it becomes to talk about your program.

Secondly, C ++ does not guarantee the intialization order of static objects defined in different translation units (.cpp files). - so if they depend on each other, you may be in trouble

+18
source share

Yes this is bad. Since you will not be able to catch exceptions and handle them, the default handler will be used. In C ++, this means the call ends ...

Example: a.cpp content

 #include <stdexcept> int f() { throw std::runtime_error("boom"); return 42; } int i = f(); int main(int argc, char* argv[]) { return 0; } 

Output: g++ a.cpp && ./a.out

 terminate called after throwing an instance of 'std::runtime_error' what(): boom Aborted (core dumped) 

You can try adding try ... catch to your main body, which will not help.

Edit: Jalf values ​​are also valid. Listen to his advice.

+7
source share

In addition to the dubious form - it will not be portable to some platforms.

+1
source share

As you indicate, this is allowed. In the last company I worked with when such a situation arose, we made it a policy to add an appropriate comment to main (), to indicate for which variables this applies. If you have a bad situation, try to do your best.

+1
source share

Using global / static objects with nontrivial constructors and destructors is terrible . I saw quite a lot of huge software projects that were in disaster due to the uncontrolled use of global / static objects and single shades.

The problem is not that it is code that runs outside of main . It is that these objects are built and destroyed in an uncontrolled manner .

In addition, I find it generally bad practice to use global variables anyway (even regular variables), with some exceptions. Each piece of code must be executed in a well-defined context, and all variables must belong to it.

0
source share

This is not a bad form at all , and it does not confuse. Static initialization is a deliberate language feature. Use it when you need to. The same with global. Use them when you need to. Like any function, knowing when it is appropriate and knowing its limitations is part of a powerful programmer.

Bad form restructures a completely different program to avoid globalization or static initialization.

0
source share

I need to go so far as to say that this is a bad form for non-PODs, especially if you work in a team primarily because of problems with the initialization order, which can easily arise because of this.

 // the following invokes undefined behavior. static bool success=cout<<"hello world\n"; 

Usually people do not write code as described above, but consider whether success was initialized by the return value of another function. Now, any temptation to use cout or cerr or any other global object in this function has caused the same undefined behavior.

For custom types with constructors and destructors, consider an alternative method in which initializing access:

 static Foo& safe_static() { static Foo f; return f; } 

Unfortunately, this also has thread safety issues, so some kind of blocking mechanism is needed to build "f" if you are accessing safe_static at the same time.

Nevertheless, I think that we should try to make everything simple. Unfortunately, when it comes to user-defined objects defined in the file area, it's too easy to run into undefined behavior. The little extra effort needed to write something like safe_static above can prevent a lot of headaches.

Exceptions are another point. If your static objects are thrown from your constructor, then you have no way to catch an exception. If you want your application to be really reliable and even handle errors on startup, you need to carefully structure your code (for example: have try / catch blocks in the constructors for objects created in the file area so that the exception is not thrown outside of ctor, and also avoid initializer lists that drop).

If you work as a team, you might think of yourself: "Oh, I do not get access to any other global groups in my class, I could also make it simple global with internal communication in the file area." Then this may be true, but before you find out, your employee adds another global variable and tries to access it from the constructor of your class. Suddenly, you have undefined behavior that might not even appear as a problem on the main platform that you are aiming for, just so that your code crashes and does other strange things when you try to move your code to another place.

This is really not worth the potential IMO headaches, and this is a problem that is much easier to avoid than fix.

0
source share

All Articles