为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++
慕沐林林 2019-07-06 15:49:30
查找C+静态初始化顺序问题我们遇到了一些问题静态初始化顺序失败,我正在寻找一种方法来梳理大量的代码,以找到可能出现的情况。对于如何有效地做到这一点,有什么建议吗?编辑:关于如何解决静态初始化顺序问题,我得到了一些很好的答案,但这并不是我的问题。我想知道如何找到受这个问题影响的对象。在这方面,Evan的回答似乎是迄今为止最好的;我不认为我们可以使用valrun,但是我们可能有一些内存分析工具可以执行类似的功能。这只会捕获问题,只有当初始化顺序对给定的构建是错误的,并且顺序可以随每个构建而改变。也许有一个静态分析工具能捕捉到这一点。我们的平台是运行在AIX上的IBMXLC/C+编译器。
查看完整描述

3 回答

?
慕婉清6462132

TA贡献1804条经验 获得超2个赞

解决初始化顺序:

首先,这只是一个暂时的解决方案,因为您有一些全局变量,您正试图摆脱这些变量,但只是还没有时间(您最终会处理掉它们,不是吗?:-)

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.
        }};


查看完整回答
反对 回复 2019-07-06
?
BIG阳

TA贡献1859条经验 获得超6个赞

根据编译器的不同,可以在构造函数初始化代码中放置断点。在Visualc+中,这是_initterm函数,给出要调用的函数列表的开始和结束指针。

然后进入每个函数以获得文件和函数名(假设您已经编译了调试信息)。一旦您有了名称,就退出函数(备份到_initterm)并继续到_initterm出口。

这给了你静态初始化器,不仅仅是代码中的那些-这是获取详尽列表的最简单方法。你可以过滤掉那些你无法控制的(比如第三方库中的那些)。

这一理论适用于其他编译器,但函数的名称和调试器的功能可能会发生变化。


查看完整回答
反对 回复 2019-07-06
  • 3 回答
  • 0 关注
  • 363 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信