2012-05-19 33 views
5

我想獲得以下安裝正確的調用順序:如何執行析構函數

一個給定的應用程序(具有多個源文件,編譯單元)在許多編譯單元定義class A類型的全局變量。 這些應該由一個新的「管理」來引入class B(其中只有一個實例應該存在),這是因爲在創建時它們在B類的實例處「註冊」它們並且在銷燬「簽出」時註冊它們自己。

設置構造函數的工作是相當直接的。人們可以使用:

types.h

class B { 
    static B& Instance() { 
    static B singleton; 
    return singleton; 
    } 
    void registerA(const A& a) { 
    // whatever 
    } 
}; 


class A { 
    A() { B::Instance().registerA(this); } 
}; 

如何獲得的析構函數嗎?如果使用:

class A { 
    A() { B::Instance().registerA(this); } 
    ~A() { B::Instance().signoffA(this); } 
}; 

那麼B析構函數可能是A析構函數之前調用。 然後,A類的實例在B剛創建的實例中籤發。

測試用例將在一個命名空間的多源文件設置爲class A情況下的定義:

file1.cc

#include "types.h" 
namespace C { 
    A a; 
} 

file2.cc

#include "types.h" 
namespace C { 
    A b; 
} 

我想上能做到如此用Boost智能指針很容易。但是,如果可能的話,我想避免使用額外的庫來保持儘可能低的依賴性。

有一件事可能會有所幫助:所有全局變量都位於命名的命名空間中。

+0

請修復您的縮進和範圍界定。 –

+0

另外,請考慮創建一個簡短的連貫測試用例來說明您的'A'實例是否與其他一切相關。目前有點令人困惑。 –

+0

請注意,'register'是C++和C中的關鍵字,因此您的代碼無法編譯。 –

回答

4

我覺得你很好。在「終止」這裏的3.6.3:如果構造函數或靜態存儲對象的動態初始化的完成之前的另一個測序

,第二的析構函數完成之前的測序啓動第一個析構函數。

假設你有以下設置:

struct A; 

struct B 
{ 
    static B & get() { static B impl; return impl; } 
    void registrate(A *); 

private: 
    B() { /* complex stuff */ } 
    // ... 
}; 

struct A { A() { B::get().registrate(this); } }; 

A a1; 

現在無論發生什麼事,靜態A型對象的第一個構造函數會調用B::get(),其完成之前序列靜態impl對象的構造第一個A-建造者。通過上面的條款,這保證了B impl對象的析構函數在之後的之後的所有A -destructors被排序。

+0

引用的語句是不是指兩個對象都是靜態存儲持續時間的情況?在我的情況下,只有一個是「靜態」。 – ritter

+0

我不明白:「靜態A型的第一個構造函數」。 'A'不是靜態的。 – ritter

+0

@Frank:「靜態」並不意味着你的想法。示例中的所有內容都有靜態存儲時間。關鍵字'static'只是用靜態存儲持續時間來創建對象的許多方法之一。 –

2

B實例是靜態的,因此在創建B單例之後,它將超過創建的任何A實例。

+0

如果所有對象都在同一個編譯單元中,這當然是正確的。這裏不是這種情況。我不確定是否在編譯單元中也會延遲靜態對象銷燬 – ritter

+0

@Frank我無法看到它如何不適用於各個編譯單元。 – juanchopanza

+0

是的,設置沒問題。但是原因在於調用構造函數的順序以及靜態的事實。如果你同時指的是兩種情況,你說得對 – ritter