确保全局变量的初始化顺序正确

Guaranteeing correct initialization order of global variables

本文关键字:顺序 初始化 全局变量 确保      更新时间:2023-10-16

我已经实现了表示枚举可能性的自定义类,类似于本文:

// 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)来初始化另一个翻译单元中的全局变量时,我遇到了问题。我知道发生这种情况是因为没有定义哪个翻译单元全局变量首先初始化。如何解决初始化排序问题?

我能想到的唯一解决方案是使用漂亮的计数器。但我不知道如何在不影响枚举类语法的情况下使用它。我正在考虑在Color中添加set()方法。然后我可以在一个漂亮的类似计数器的初始化器中调用这个方法:

// 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方法可能会在尚未构造的对象上调用。这样可以吗?还是行为未定义?如何更好地解决初始化顺序不明确的问题?

在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);    
//...

首先不要使用全局对象。相反,使用以下功能:

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对象的构造函数。

由于您的Colour对象是轻量级的,因此可以只使用静态函数。

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);
};

唯一的问题是不能将这些对象传递给期望指针或非常量引用的函数(但在这种情况下,非常量引用可能毫无意义)。