2012-07-12 89 views
0

我已經實現表示枚舉可能性相若方式來this article自定義類:保障全局變量的正確初始化順序

// Color.h 

class Color { 
public: 
    static const Color Red; 
    static const Color Green; 
    static const Color Blue; 
    //... 
private: 
    explicit Color(int code); 
    //... 

    int code; 
    static std::set<Color> colors; 
}; 

// Color.cpp: 

const Color Color::Red(1); 
const Color Color::Green(2); 
const Color Color::Blue(3);  
//... 

現在我有問題時,我想使用的實例Color例如:Color::Red初始化的全局變量在另一個翻譯單位。我知道這是因爲它沒有定義哪個翻譯單元全局變量是首先被初始化的。初始化排序問題如何解決?

我能想到的唯一解決方案是使用漂亮的計數器。但是我無法知道如何在不影響枚舉類語法的情況下使用它。我正在考慮將set()方法加入Color。然後,我可以像初始化一個漂亮的反調用這個方法:

// Color.h 

class Color { 
public: 
    void set(int code); 
    //... 
private: 
    Color() { /* empty */} 
    //... 
}; 

static class ColorInitializer { 
    ColorInitializer() { 
     static bool initialized = false; 
     if(initialized) 
      return; 

     Color::Red.set(1); 
     Color::Green.set(1); 
     Color::Blue.set(1); 
     initialized = true; 
    } 
} colorInitializer; 

// Color.cpp 

const Color Color::Red; 
const Color Color::Green; 
const Color Color::Blue; 

但我看到這裏的問題是,set方法可以在一個尚未構造的對象調用。這是好的還是行爲未定義?如何更好地解決未定義初始化順序的問題?

+0

我沒有使用C++ 11的經驗,但我嚴重懷疑'ColorInitializer'的整個方法並不好。使用'{...}'等進行初始化可以更好地進行調查,等等。您爲第一個代碼示例獲取什麼錯誤? – 2012-07-12 13:17:46

+0

@Kirill Kobelev:我沒有收到任何編譯錯誤,它只是一個未定義的行爲。變量在使用時可能會被初始化,也可能不會被初始化。 – 2012-07-12 13:21:06

+0

然後我會懷疑這種行爲與你的特定班級沒有關係。嘗試隔離問題。鏈接器有問題嗎? – 2012-07-12 13:25:42

回答

3

在C++ 11(如果你能負擔得起使用它),你可以使用擴展的常量表達式功能:

class Color { 
public: 
    static constexpr const Color Red; 
    static constexpr const Color Green; 
    static constexpr const Color Blue; 
private: 
    constexpr explicit Color(int code); 
    //... 
}; 

// Color.cpp: 

constexpr Color Color::Red(1); 
constexpr Color Color::Green(2); 
constexpr Color Color::Blue(3);  
//... 
+0

非常感謝,不幸的是,這是在一箇舊的項目中使用,至少現在C++ 11不是一個選項。 – 2012-07-12 13:18:03

2

不要擺在首位使用全局對象。相反,使用函數:

class Color { 
public: 
    static const Color &Red() { 
     static const Color c(1); 
     return c; 
    } 

    static const Color &Green() { 
     static const Color c(2); 
     return c; 
    } 

    static const Color &Blue() { 
     static const Color c(3); 
     return c; 
    } 
private: 
    explicit Color(int code); 
    //... 
}; 

您現在可以使用這些函數來初始化其他對象;調用它們將確保調用Color對象的構造函數。

+0

不幸的是,**這在C++ 03 **上不是線程安全的(儘管它在C++ 11和最新版本的gcc上)。另請參閱:http://stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems/335746#335746 – 2016-01-15 13:29:40

2

由於您的Color對象是輕量級的,只需使用靜態函數即可。

class Color { 
public: 
    static Color Red() { return Color(1); } 
    static Color Green() { return Color(2); } 
    static Color Blue() { return Color(3); } 
private: 
    explicit Color(int code); 
}; 

與此唯一的問題是你不能將這些對象,以期待指針或者非const引用(但在這種情況下,非const引用可能是無意義反正)功能。