14

ヘッダーファイルのみで構成されるライブラリを開発しています。これまでのところ、クラスのみが含まれていますが、問題ありません。ただし、一部の関数を実装するには、ライブラリ内にライブラリ全体でアクセス可能な不変のデータ(つまり、クラスインスタンスデータではない)が必要になるようになりました。明らかに、グローバルデータをヘッダーファイルに入れることはできません。そうしないと、ヘッダーであるすべて#includeのコンパイルユニットにシンボルの定義があり、リンク時に複数の定義エラーが発生します。

static関数内のデータを変数にしてそのデータへのポインターを返すだけで、ライブラリにコンパイルユニットを追加しなくても、クラスに静的データを含めることができる回避策を見つけたようです。

class StaticData {
public:
    void doSomething() { /* this uses getData */ }
    void doSomethingElse() { /* this does too */ }

private:
    static int* getData() {
        static int array[] { 1, 2, 3, 4 };

        return array;
    }
};

これは正常に機能しているように見えますが、ヘッダーファイルstaticの関数の関数データが​​どうなるかわからないことを認めなければなりません。inlineこの「ハック」には、#includeこのヘッダーが独自のバージョンのを取得するすべてのコンパイルユニットなど、意図しない影響があるのではないかと思いarrayます。コンパイラはどのようにそしてどこにそれを置くことを決定しますか?

また、これをシングルトンアンチパターンなどの実装に使用していないことにも注意してください。複数の関数が使用する必要のあるデータを格納するために使用しているだけです(そのため、それを使用する関数だけに含めることはできませんがstatic、使用したとしても、同じ質問が表示されます)。

4

2 に答える 2

10

それはいいです。array関数に外部リンケージがある限り、のコピーは1つだけであることが保証されています。C++標準は次のように述べています。

7.1.2 / 4 externインライン関数の静的ローカル変数は、常に同じオブジェクトを参照します。

于 2012-09-06T17:54:05.190 に答える
0

別のアプローチ...

template<typename> class ArrayData {
    friend class ClassWithArray;
    static int array[4];
};

class ClassWithArray :
    ArrayData<ClassWithArray>
{
public:
    void doSomething() { 
        /* this uses getData */ 
        array[0] = 1;
        array[1] = 2;
        array[2] = 3;
        array[3] = 4;
    }
    void doSomethingElse() { 
        /* this does too */ 
        array[0] = 4;
        array[1] = 3;
        array[2] = 2;
        array[3] = 1;
    }
};

int ArrayData<ClassWithArray>::array[4] = { 1, 2, 3, 4 };

ジェネリック実装

template<typename T> class ArrayDataT 
{
    friend T;
    static int array[4];
};

template<typename T>
int ArrayDataT<T>::array[4] = { 1, 2, 3 ,4 };

class DerivedFromArrayDataT :
    ArrayDataT<DerivedFromArrayDataT>
{

};
于 2017-05-18T15:22:47.803 に答える