Finding C++ static initialization order problems

后端 未结 12 800
情话喂你
情话喂你 2020-11-22 10:10

We\'ve run into some problems with the static initialization order fiasco, and I\'m looking for ways to comb through a whole lot of code to find possible occurrences. Any s

相关标签:
12条回答
  • 2020-11-22 10:24

    Gimpel Software (www.gimpel.com) claims that their PC-Lint/FlexeLint static analysis tools will detect such problems.

    I have had good experience with their tools, but not with this specific issue so I can't vouch for how much they would help.

    0 讨论(0)
  • 2020-11-22 10:27

    perhaps use valgrind to find usage of uninitialized memory. The nicest solution to the "static initialization order fiasco" is to use a static function which returns an instance of the object like this:

    class A {
    public:
        static X &getStatic() { static X my_static; return my_static; }
    };
    

    This way you access your static object is by calling getStatic, this will guarantee it is initialized on first use.

    If you need to worry about order of de-initialization, return a new'd object instead of a statically allocated object.

    EDIT: removed the redundant static object, i dunno why but i mixed and matched two methods of having a static together in my original example.

    0 讨论(0)
  • 2020-11-22 10:30

    Solving order of initialization:

    First off, this is just a temporary work-around because you have global variables that you are trying to get rid of but just have not had time yet (you are going to get rid of them eventually aren't you? :-)

    class A
    {
        public:
            // Get the global instance abc
            static A& getInstance_abc()  // return a reference
            {
                static A instance_abc;
                return instance_abc;
            }
    };
    

    This will guarantee that it is initialised on first use and destroyed when the application terminates.

    Multi-Threaded Problem:

    C++11 does guarantee that this is thread-safe:

    §6.7 [stmt.dcl] p4
    If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

    However, C++03 does not officially guarantee that the construction of static function objects is thread safe. So technically the getInstance_XXX() method must be guarded with a critical section. On the bright side, gcc has an explicit patch as part of the compiler that guarantees that each static function object will only be initialized once even in the presence of threads.

    Please note: Do not use the double checked locking pattern to try and avoid the cost of the locking. This will not work in C++03.

    Creation Problems:

    On creation, there are no problems because we guarantee that it is created before it can be used.

    Destruction Problems:

    There is a potential problem of accessing the object after it has been destroyed. This only happens if you access the object from the destructor of another global variable (by global, I am referring to any non-local static variable).

    The solution is to make sure that you force the order of destruction.
    Remember the order of destruction is the exact inverse of the order of construction. So if you access the object in your destructor, you must guarantee that the object has not been destroyed. To do this, you must just guarantee that the object is fully constructed before the calling object is constructed.

    class B
    {
        public:
            static B& getInstance_Bglob;
            {
                static B instance_Bglob;
                return instance_Bglob;;
            }
    
            ~B()
            {
                 A::getInstance_abc().doSomthing();
                 // The object abc is accessed from the destructor.
                 // Potential problem.
                 // You must guarantee that abc is destroyed after this object.
                 // To guarantee this you must make sure it is constructed first.
                 // To do this just access the object from the constructor.
            }
    
            B()
            {
                A::getInstance_abc();
                // abc is now fully constructed.
                // This means it was constructed before this object.
                // This means it will be destroyed after this object.
                // This means it is safe to use from the destructor.
            }
    };
    
    0 讨论(0)
  • 2020-11-22 10:30

    Other answers are correct, I just wanted to add that the object's getter should be implemented in a .cpp file and it should not be static. If you implement it in a header file, the object will be created in each library / framework you call it from....

    0 讨论(0)
  • 2020-11-22 10:34

    If your project is in Visual Studio (I've tried this with VC++ Express 2005, and with Visual Studio 2008 Pro):

    1. Open Class View (Main menu->View->Class View)
    2. Expand each project in your solution and Click on "Global Functions and Variables"

    This should give you a decent list of all of the globals that are subject to the fiasco.

    In the end, a better approach is to try to remove these objects from your project (easier said than done, sometimes).

    0 讨论(0)
  • 2020-11-22 10:36

    Depending on your compiler, you can place a breakpoint at the constructor initialization code. In Visual C++, this is the _initterm function, which is given a start and end pointer of a list of the functions to call.

    Then step into each function to get the file and function name (assuming you've compiled with debugging info on). Once you have the names, step out of the function (back up to _initterm) and continue until _initterm exits.

    That gives you all the static initializers, not just the ones in your code - it's the easiest way to get an exhaustive list. You can filter out the ones you have no control over (such as those in third-party libraries).

    The theory holds for other compilers but the name of the function and the capability of the debugger may change.

    0 讨论(0)
提交回复
热议问题