0

この記事と同様に、列挙の可能性を表すカスタム クラスを実装しました。

// 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メソッドがまだ構築されていないオブジェクトで呼び出される可能性があることです。それはOKですか、それとも動作は未定義ですか? 未定義の初期化順序の問題をより適切に解決するには?

4

3 に答える 3

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);    
//...
于 2012-07-12T13:13:38.207 に答える
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それらを呼び出すと、オブジェクトのコンストラクターが確実に呼び出されます。

于 2012-07-12T13:22:41.430 に答える
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 参照はおそらく無意味です)。

于 2012-07-12T13:29:11.100 に答える