2012-04-30 123 views
1

得到具有以下原因不明的行爲:非靜態全局對象VS全局指針到動態對象

情況1:

a.cpp編譯爲一個.dll庫和main.cpp

在主()使用
Bar b; 

//constr 
Bar::Bar(){ 
    //... initialize members 
} 

//private library init 
Bar::init(){ ...} 

//public API init 
bool lib_init(){ 
    b.init(); 
} 

從我所瞭解的情況來看,這種方法可能會因爲全局變量的未定義初始化行爲而失敗。

情況2:

a.cpp編譯爲一個.dll庫和main.cpp

Bar* b; 

//constr 
Bar::Bar(){ 
    //... initialize members 
} 

//private library init 
Bar::init(){ ...} 

//public API init 
bool lib_init(){ 
    b = new Bar; 
    b->init(); 
} 

這一次它的工作原理,當使用動態分配在主()使用。

案例3(最令人驚訝的)

a.cpp編譯爲一個.dll庫和main.cpp

static Bar& getBarObj() 
{ 
    static Bar g_objBar; 
    return g_objBar; 
} 

//constr 
Bar::Bar(){ 
    //... initialize members 
} 

//private library init 
Bar::init(){ ...} 

//public API init 
bool lib_init(){ 
    getBarObj().init(); 
} 

與之相對第1種情況,其中酒吧的obj實例可能是不確定的主要使用() ,在情況3中「根據請求」使用它。然而,案例3提供了與案例1相同的行爲。

而我的問題是......任何人都可以解釋這裏發生了什麼? 一切是建立與VC2008釋放模式(對調試模式這個凸出別無選擇)

+2

什麼「不明原因的行爲」你看見了什麼? – Mat

+0

在Bar constr中,我有一個初始化循環。它的一個成員是一個固定大小的struct Foo類型的數組,在「a.h」中定義。例如,不是迭代SIZE_OF_ARRAY = 8次,循環迭代爲50K次... – BegemoD

+0

請將其編輯到您的問題中,_including相關的code_ - 您的實際問題沒有任何描述(已經很長)的文章。在a.h中的 – Mat

回答

0

從不同的文件(你肯定有一個案例)是未定義在C++中的全局變量初始化的順序。這意味着如果你依賴Bar b在全局初始化期間在不同的編譯單元中構建,你的程序是未定義的。

爲什麼案例3應該工作,是因爲它迫使您使用函數來引用Bar b,並且此函數保證Bar b將在此函數返回時構建。

如果您告訴我們您正在獲取什麼確切的未定義行爲,並提供最少量的代碼進行分析,我們可能會進一步提供幫助。

P.S.你的Bar構造函數依賴於另一個全局構造?

+0

,除了Bar類定義,我有一個Foo結構。 Bar的一個成員是Foo的一個固定大小的數組: – BegemoD

+0

難道是因爲'SIZE_OF_ARRAY'是一個全局的變量,當你到達'Bar'構造函數時,它不會被初始化?只有這可能導致50k次迭代。你可以在初始化'Bar'之前打印'SIZE_OF_ARRAY'的值以確保它已被初始化? – Irfy

0

由於b的構造本質上屬於鏈接順序(不受C++規範控制:它對於C++是未定義的行爲,但行爲可以由鏈接器定義!),因此情況1可能失敗 In任何情況下,一旦您致電lib_initb被授權構建爲lib_initb留在同一模塊中。

情況3在需要的時候構造b,並且將以與所有其他靜態和全局對象相反的順序在終止時銷燬它。 如果反過來Bar::Bar()電話具有靜態Foo一個foo_init()內,這可能與老編譯器會給出一些問題:你需要BarBar需求FooBarFoo之前創建和FooBar該墊還需要之前銷燬。 這個事實應該自2003年以後發生。需要破壞調度,工程竣工以後發生(這樣Foo構造函數之前Bar構造函數,因此酒吧析構函數將在終止前Foo析構函數被調用完成

案例二是「醜」:適用於cotruction樣病例3(創造需求)butwith兩個問題:

  • 指針應是靜態的,只是爲了避免在多個呼叫的情況下創建多個對象lib_init()和...
  • 誰永遠不會破壞酒吧操作系統?會在終止時回憶回憶,但是沒有人會叫。

案例2 shold有可能是更好的定義爲

void lib_init() 
{ 
    static std::unique_ptr<Bar> p(new Bar); 
    p->init(); 
} 

但是這將使它像案例3.