查找C+静态初始化顺序问题

查找C+静态初始化顺序问题

我们遇到了一些问题静态初始化顺序失败,我正在寻找一种方法来梳理大量的代码,以找到可能出现的情况。对于如何有效地做到这一点,有什么建议吗?

编辑:关于如何解决静态初始化顺序问题,我得到了一些很好的答案,但这并不是我的问题。我想知道如何找到受这个问题影响的对象。在这方面,Evan的回答似乎是迄今为止最好的;我不认为我们可以使用valrun,但是我们可能有一些内存分析工具可以执行类似的功能。这只会捕获问题,只有当初始化顺序对给定的构建是错误的,并且顺序可以随每个构建而改变。也许有一个静态分析工具能捕捉到这一点。我们的平台是运行在AIX上的IBMXLC/C+编译器。


慕沐林林
浏览 367回答 3
3回答

慕婉清6462132

解决初始化顺序:首先,这只是一个暂时的解决方案,因为您有一些全局变量,您正试图摆脱这些变量,但只是还没有时间(您最终会处理掉它们,不是吗?:-)class A{     public:         // Get the global instance abc         static A& getInstance_abc()  // return a reference         {             static A instance_abc;             return instance_abc;         }};这将保证它在第一次使用时被初始化,并在应用程序终止时销毁。多线程问题:C+11是吗?确保这是线程安全的:§6.7[stmt.dcl]p4如果在初始化变量时控件同时输入声明,则并发执行应等待初始化完成。然而,C+03确实不正式保证静态函数对象的构造是线程安全的。所以严格来说getInstance_XXX()方法必须用关键部分来保护。好的一面是,GCC有一个显式的补丁作为编译器的一部分,它保证每个静态函数对象只初始化一次,即使在线程存在的情况下也是如此。请注意:不要使用双重检查锁定模式以避免锁定的成本。这在C+03中是行不通的。创作问题:在创建时,没有任何问题,因为我们保证在可以使用它之前创建它。销毁问题:在对象被销毁后访问该对象存在一个潜在的问题。只有当您从另一个全局变量的析构函数(通过全局,我指的是任何非局部静态变量)访问对象时,才会发生这种情况。解决办法是确保你强制执行毁灭的顺序。记住,破坏的顺序与建筑的顺序完全相反。因此,如果您访问析构函数中的对象,则必须确保该对象未被销毁。要做到这一点,您必须保证在构造调用对象之前,对象是完全构造的。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.         }};

BIG阳

根据编译器的不同,可以在构造函数初始化代码中放置断点。在Visualc+中,这是_initterm函数,给出要调用的函数列表的开始和结束指针。然后进入每个函数以获得文件和函数名(假设您已经编译了调试信息)。一旦您有了名称,就退出函数(备份到_initterm)并继续到_initterm出口。这给了你全静态初始化器,不仅仅是代码中的那些-这是获取详尽列表的最简单方法。你可以过滤掉那些你无法控制的(比如第三方库中的那些)。这一理论适用于其他编译器,但函数的名称和调试器的功能可能会发生变化。
打开App,查看更多内容
随时随地看视频慕课网APP