2013-02-17 72 views
2

我遇到了一個初始化命名空間中的一些const對象的問題。我有類似下面的命名空間:初始化命名空間中的const對象

namespace myNamespace{ 
    const std::string HI = "Hi"; 
    const std::string BYE = "Bye"; 

    inline std::vector<std::string> createHiAndByeVector(){ 
     std::vector<std::string> temp; 
     temp.push_back(HI); 
     temp.push_back(BYE); 
     return temp; 
    } 

    const std::vector<std::string> HI_AND_BYE = createHiAndByeVector(); 
} 

如果我調試的初始化,我可以看到,無論HIBYE得到分配的字符串文字。執行繼續到initialziae HI_AND_BYE,但是當我們進入createHiAndByeVector()函數時,HIBYE都不再有任何值。然後在push_back()方法中出現分段錯誤。如果我看看調用堆棧,我會看到該行:__static_initialization_and_destruction_0()。到底是怎麼回事?我的對象在構建後立即被破壞?

+0

爲什麼這麼繁瑣的:你只能說'的std ::矢量常量HI_AND_BYE { 「你好」, 「再見」};'。 – 2013-02-17 01:36:47

+1

所有這些定義都出現在相同的翻譯單元(.cpp文件)中? – 2013-02-17 01:38:19

+0

你有另一個靜態成員依賴於'HI_AND_BYE'?一種靜態的初始化訂單問題 – billz 2013-02-17 01:57:28

回答

-1

我認爲這是由於Initialization Fiasco。以下鏈接可能對您有所幫助問題是全局/靜態變量是以隨機方式初始化的。沒有特定的初始化順序。所以也許你的HI_AND_BYE在HI或BYE初始化之前被初始化。

Finding C++ static initialization order problems

http://www.parashift.com/c++-faq-lite/static-init-order.html

+1

單個翻譯單元中的對象的初始化順序是明確定義的,它是按它們聲明的順序。請注意,例如parashift的C++ FAQ提到了「存在於獨立源文件中」的對象。 – 2013-02-17 10:20:54

+0

啊,謝謝你指出:) – Deamonpog 2013-02-17 10:55:12

1

我的猜測是,這裏的問題是違反了一個定義規則(ODR)的。這裏的猜測是,這段代碼實際上是在一個頭文件中,這也是您將函數聲明爲內聯的原因。

現在,該代碼被編譯爲多個翻譯單元(.cpp文件),TU1和TU2。這導致兩組常量和內聯函數。現在,鏈接時,常量彼此獨立存在,因爲它們具有內部鏈接(名稱空間級別的常量會導致此問題)。但是,該函數沒有內部鏈接,而是指示鏈接器通過inline丟棄所有實例,但只有一個實例。現在,剩下的一個用於初始化TU1和TU2中的矢量,但它使用來自其中一個的常量字符串。根據何時初始化,這是未定義的,它可以工作或不工作。這基本上是上面Deamonpog提到的初始化順序失敗。

回到ODR,問題在於內聯函數被編譯了兩次,但它們並不相同,因爲它們隱含地引用了不同的字符串常量。當標題中有匿名命名空間時會出現類似的問題。順便說一句:除此之外,這個問題與命名空間無關!有兩種方法可以解決這個問題:

  1. 使init函數也是靜態的。這將所有這些常數和功能從其他翻譯單位的弟兄中分離出來。
  2. 您只需聲明(extern string const BYE;)標題中的常量並在單獨的TU中實施它們(string const BYE = "Bye!";)。這樣你只有一個可以被程序的不同部分共享的單個實例。
+0

感謝您的詳細解答。我認爲名字空間中的函數是隱含的,就像兩個字符串「HI」和「BYE」一樣是靜態的。在這種情況下,爲什麼會有多個「副本」的字符串?我試圖避免選項2,因爲我正在製作僅頭文件庫;實際上,這正是我試圖重寫的場景。 – Wagan8r 2013-03-15 01:38:10