2012-09-06 10 views
14

ヘッダーファイルのみで構成されるライブラリを開発しています。これまでは、クラスだけが含まれていましたが、これはうまくいきました。しかし、私は、いくつかの関数の実装のために、ライブラリー全体にアクセス可能な不変のデータ(つまり、クラス・インスタンス・データではない)をライブラリーに持っていなければならないことがあります。明らかに、ヘッダーファイルにグローバルデータを置くことはできません。そうでなければ、ヘッダーにシンボルの定義があり、リンク時に複数の定義エラーが発生するすべてのコンパイル単位を入れることはできません。ヘッダー専用ライブラリの静的データ

関数に変数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; 
    } 
}; 

これは正常に動作しているように見えるが、私はヘッダファイルにinline機能でstaticデータを機能 - するために何が起こるか分からないということを認めなければなりません。私は、この "ハック"には、arrayという独自のバージョンを取得しているこのコンパイル単位のような、意図しない影響があるかどうか疑問に思っています。コンパイラはどこにどのように配置するのですか?

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

答えて

9

これは問題ありません。関数には外部リンケージがある限り、arrayのコピーが1つしかないことが保証されています。

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

+0

ああ、それが救済です。私はこれがC++ 11と同様にC++ 03にも当てはまると仮定していますか?これは私の質問に実用目的で答えるが、面白いことに、コンパイラがどのようにデータ/関数定義を置くかを決定する方法に関するインプリメンテーションに依存しない情報はあるか? –

+0

C++ 03の表現はまったく同じです。私は、コンパイラが、インライン関数とその静的なローカルのシンボルにフラグを設定したり、特別なセクションに置いたりして、見つかった最初のオカレンスをインクルードして重複を破棄するようリンカーに指示します。しかし、私はそれについての詳細を知らない。 –

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> 
{ 

}; 
関連する問題