2016-01-19 89 views
4

是什麼區別:C++ 11中的靜態局部變量?

class A { 
public: 
    static const A& GetInstance() { 
    static A a; 
    return a; 
    } 
}; 

class B { 
    public: 
    static const B* GetInstance() { 
    static B* b = new B; 
    return b; 
    } 
}; 

? A和B之間單身人士的生活有什麼不同?對象的內存位置?任何差異一般?

回答

8

這兩種情況下物體的壽命是不同的。 C++保證靜態局部對象將以與其構造相反的順序銷燬。在這兩種情況下,首次調用GetInstance時都會發生施工。

但是,在第二種情況下,變量b被分配了一個分配有new的指針。當從靜態存儲中刪除b時,該內存將保留,直到堆最終被拆除。在那個階段,它將被視爲「泄漏」,並且B的析構函數(如果有)將永遠不會被調用。

這將是更好地實現基於指針的方法是這樣的:現在

class B { 
    public: 
    static const B* GetInstance() { 
    static std::unique_ptr<B> b(new B); 
    return b.get(); 
    } 
}; 

B::~B()將被調用(如適用),並且內存將在b被銷燬正確刪除,並且使用壽命和你的第一個例子一樣。

這只是留下你關於內存位置的問題。位置會有所不同。靜態變量通常存儲在程序的數據段中,而以new分配的任何內容都將存儲在堆中。

+0

作爲一種事後,也有可能是在程序行爲時A''或'B'過大而差異分別適合堆或數據段。如果'B'太大,那麼'new B'應該拋出'std :: bad_alloc'。在'A'的情況下,我不確定是否拋出可捕獲的異常,或者程序是否會發生seg-fault和死亡。 – paddy

0

添加到第一個答案,2條評論(假設你想創建一個單身人士)。

  1. 如果2個線程試圖訪問靜態實例重疊,如果訪問是第一個訪問(當構造函數運行時),則存在線程/競爭問題。如今,C++具有編譯器/標準支持,可以自動使此靜態單例初始化線程安全。
  2. 在堆大小寫中,您不希望每次都在堆上創建新實例。只需檢查nullptr,並且只在堆上第一次創建實例。

編輯:下面是一個SO問題,其中包含答案相關的裁判標準:Heap/dynamic vs. static memory allocation for C++ singleton class instance

+0

正如問題中所提到的,在C++ 11中:(1)和(2)都是由編譯器保證的。 (1)編譯器保證* static *局部變量初始化是線程安全的。 (2)編譯器保證* static *局部變量初始化只會被執行一次,所有後續調用該函數將跳過靜態局部變量的重新初始化(因此每次都不會創建新的實例)。 – iBrAaAa

+0

@iBrAaAa?這個問題沒有提到標準的任何保證。相關部分是6.7.4,參見例如。 HTTP://計算器。com/questions/15062767/heap-dynamic-vs-static-memory-allocation-for-c-singleton-class-instance因此,使用函數靜態變量意味着你可以通過同步的標準獲得幫助。 –