C++ 靜態(tài)變量析構(gòu)順序的分析與控制

1. 了解變量析構(gòu)順序的必要性

??大多數(shù)時間里,我們更關(guān)注的是變量的初始化順序,因為我們需要確保使用到的變量都是初始化好的變量。然而,當(dāng)項目變大、變復(fù)雜的時候,我們可能就會開始考慮程序的退出問題,尤其是多線程程序的退出,變量的析構(gòu)順序可能會影響到程序是否能優(yōu)雅、安全地退出。

2. 全局(靜態(tài))變量的析構(gòu)順序

??我們都知道C++規(guī)范規(guī)定,變量析構(gòu)的順序和構(gòu)造的順序是相反的。對于在同一個編譯單元內(nèi)的全局(靜態(tài))變量的初始化順序,與他們聲明的順序是相同的,而析構(gòu)的順序則與初始化的順序是相反的;對于不在同一個編譯單元的全局(靜態(tài))變量的初始化順序是不確定的。

3. 局部靜態(tài)變量的析構(gòu)順序

??相對復(fù)雜的是局部靜態(tài)變量的初始化與析構(gòu)流程。對于局部靜態(tài)變量,大家都知道的一點就是初始化是發(fā)生在函數(shù)第一次運行的時候,所以我們可以推導(dǎo)出,局部靜態(tài)變量的初始化肯定是晚于全局(靜態(tài))變量的,所以其析構(gòu)肯定是早于全局(靜態(tài))變量的。

4. 析構(gòu)順序的分析

??前面我們直接給出了結(jié)論,下面用地段代碼來看一下局部靜態(tài)變量晚于全局(靜態(tài))變量析構(gòu)的原因:

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

然后我們編譯成匯編語言,會看到,當(dāng)程序定義一個結(jié)構(gòu)體變量時,會在定義結(jié)束后調(diào)用 __cxa_atexit,來注冊程序exit時調(diào)用的析構(gòu)函數(shù)。全局(靜態(tài))變量位于代碼段,構(gòu)造會在進(jìn)入main函數(shù)之前,對于局部靜態(tài)變量,構(gòu)造函數(shù)會在main函數(shù)調(diào)用func時,注冊晚于全局變量,所以析構(gòu)的調(diào)用就會早于全局變量的析構(gòu)函數(shù)。
如果想要控制一個局部靜態(tài)變量的析構(gòu),晚于一個全局(靜態(tài))變量,則可以將對函數(shù)的調(diào)用,放到全局(靜態(tài))變量的構(gòu)造函數(shù)內(nèi)調(diào)用

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

最后補充一個結(jié)論,析構(gòu)函數(shù)的順序:

局部靜態(tài)變量 ==> attribute((destructor)) ==> 全局變量

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容