美文网首页
C++ 静态变量析构顺序的分析与控制

C++ 静态变量析构顺序的分析与控制

作者: 猿佑 | 来源:发表于2022-09-05 11:37 被阅读0次

    1. 了解变量析构顺序的必要性

      大多数时间里,我们更关注的是变量的初始化顺序,因为我们需要确保使用到的变量都是初始化好的变量。然而,当项目变大、变复杂的时候,我们可能就会开始考虑程序的退出问题,尤其是多线程程序的退出,变量的析构顺序可能会影响到程序是否能优雅、安全地退出。

    2. 全局(静态)变量的析构顺序

      我们都知道C++规范规定,变量析构的顺序和构造的顺序是相反的。对于在同一个编译单元内的全局(静态)变量的初始化顺序,与他们声明的顺序是相同的,而析构的顺序则与初始化的顺序是相反的;对于不在同一个编译单元的全局(静态)变量的初始化顺序是不确定的。

    3. 局部静态变量的析构顺序

      相对复杂的是局部静态变量的初始化与析构流程。对于局部静态变量,大家都知道的一点就是初始化是发生在函数第一次运行的时候,所以我们可以推导出,局部静态变量的初始化肯定是晚于全局(静态)变量的,所以其析构肯定是早于全局(静态)变量的。

    4. 析构顺序的分析

      前面我们直接给出了结论,下面用地段代码来看一下局部静态变量晚于全局(静态)变量析构的原因:

    #include <stdio.h>
    #include <string>
    #include <string.h>
    class A
    {
    public:
        A()
        {
        }
        A(const std::string &name)
        {
            name_ = name;
            printf("A of %s\n", name_.c_str());
        }
        ~A()
        {
            printf("~A of %s\n", name_.c_str());
        }
    private:
        std::string name_;
    };
    A a("global a");
    void test()
    {
        static A local_a("local a");
    }
    int main()
    {
        test();
        return 0;
    }
    

    然后我们编译成汇编语言,会看到,当程序定义一个结构体变量时,会在定义结束后调用 __cxa_atexit,来注册程序exit时调用的析构函数。全局(静态)变量位于代码段,构造会在进入main函数之前,对于局部静态变量,构造函数会在main函数调用func时,注册晚于全局变量,所以析构的调用就会早于全局变量的析构函数。
    如果想要控制一个局部静态变量的析构,晚于一个全局(静态)变量,则可以将对函数的调用,放到全局(静态)变量的构造函数内调用

    #include <stdio.h>
    #include <string>
    #include <string.h>
    
    void func();
    
    class A
    {
    public:
        A()
        {
        }
    
        A(const std::string &name)
        {
            name_ = name;
            printf("A of %s\n", name_.c_str());
            func();
        }
    
        ~A()
        {
            printf("~A of %s\n", name_.c_str());
        }
    private:
        std::string name_;
    };
    
    class B
    {
    public:
        B()
        {
        }
    
        B(const std::string &name)
        {
            name_ = name;
            printf("B of %s\n", name_.c_str());
        }
    
        ~B()
        {
            printf("~B of %s\n", name_.c_str());
        }
    private:
        std::string name_;
    };
    
    A a("global a");
    
    void func()
    {
        static B lb("local b");
    }
    
    int main()
    {
        return 0;
    }
    
    

    最后补充一个结论,析构函数的顺序:

    局部静态变量 ==> attribute((destructor)) ==> 全局变量

    相关文章

      网友评论

          本文标题:C++ 静态变量析构顺序的分析与控制

          本文链接:https://www.haomeiwen.com/subject/wgzenrtx.html