2012-07-12 111 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引用可能是无意义反正)功能。