C++クラスについて考えてみましょう。実行の開始時に、XMLファイルから一連の値を読み取り、このクラスの7つのデータメンバーに割り当てます。これらの値は実行全体を通じて変更されることはなく、問題のクラスのすべてのオブジェクト/インスタンスで共有する必要があります。静的データメンバーは、この動作を実現するための最も洗練された方法ですか?(もちろん、私はグローバル変数を考慮していません)
8 に答える
他の人が述べたように、この場合の静的メンバーの使用は適切なようです。それは絶対確実ではないことを覚えておいてください。グローバル データに関するいくつかの問題は、静的メンバーに適用されます。
- 静的メンバーの初期化の順序を制御することはできないため、グローバルまたは他の静的がこれらのオブジェクトを参照していないことを確認する必要があります。詳細と、この問題を回避するためのヒントについては、この C++ FAQ の質問を参照してください。
- マルチスレッド環境でこれらにアクセスする場合は、スレッドを生成する前にメンバーが完全に初期化されていることを確認する必要があります。
すっきりとしたデザインではありません。静的クラスメンバーはグローバル状態であり、グローバル状態は不良です。
これが中小規模のプロジェクトであり、自動テストの高い目標がない場合は、問題を引き起こさない可能性がありますが、あなたが尋ねたので、より良い方法があります。
よりクリーンな設計は、クラスのファクトリを作成し、ファクトリがクラスを構築するときに7つの変数をクラスに渡すようにすることです。その場合、すべてのインスタンスが同じ値を共有することを保証するのはファクトリの責任です。
そうすれば、クラスはテスト可能になり、懸念事項を適切に分離できます。
私には静的変数の良い使い方のように聞こえます。これらは変数よりも固定パラメーターとして使用しているため、値を合法的に共有する必要があります。
静的メンバーはここで機能し、完全に受け入れられます。もう1つのオプションは、これらのメンバーを保持するクラスにシングルトンパターンを使用して、それらが1回だけ構築/設定されるようにすることです。
実行の開始時に、XMLファイルから一連の値を読み取り、このクラスの7つのデータメンバーに割り当てます。これらの値は実行全体を通じて変更されることはなく、問題のクラスのすべてのオブジェクト/インスタンスで共有する必要があります。
太字の文はここのキッカーです。そのステートメントが成り立つ限り、静的変数の使用は問題ありません。これはどのように実施されますか?
それは難しいです。したがって、現在の使用でステートメントが常に真である場合は、先に進んでください。クラスを間違って使用している将来の開発者(またはあなた)から同じになりたい場合(プログラムの途中で別のXMLファイルを読み取るなど)、RasmusFarberが言うようなことをしてください。
静的クラス メンバーの適切な使用のように思えます。それらは実際には名前空間と (おそらく) 何らかの保護を備えたグローバル変数であることを忘れないでください。したがって、アプリケーションがいつか個別の「環境」またはそれぞれにこれらのグローバルのセットを必要とする何かを進化させる可能性がある場合、あなたは窮地に立たされているでしょう。
ロブが提案したように、シングルトンの使用を検討してください。これは、後で何らかの管理された環境変数に簡単に変換できます。
はい、静的データメンバーはあなたが探しているものです。ただし、静的変数の初期化/破棄の順序に注意する必要があります。C++ には、翻訳単位間で使用する前に静的変数を確実に初期化するメカニズムがありません。安全のために、singleton パターンのように見え、その問題を解決するためによく知られているものを使用してください。次の理由で機能します。
- すべての静的オブジェクトは、xml_stuff インスタンスの完全な構築後に完全に構築されます。
- C++ での静的オブジェクトの破棄の順序は、構築の完了 (コンストラクターが実行を終了したとき) とは正反対です。
コード:
class xml_stuff {
public:
xml_stuff() {
// 1. touch all members once
// => 2. they are created before used
// => 3. they are created before the first xml_stuff instance
// => 4. they will be destructed after the last xml_stuff instance is
// destructed at program exit.
get_member1();
get_member2();
get_member3();
// ...
}
// the first time their respective function is called, these
// objects will be created and references to them are returned.
static type1 & get_member1() { static type1 t; return t; }
static type2 & get_member2() { static type2 t; return t; }
static type1 & get_member3() { static type1 t; return t; }
// ... all other 7 members
};
現在、xml_stuff::get_memberN() によって返されるオブジェクトは、すべての xml_stuff インスタンスの有効期間全体にわたって有効です。これは、これらのメンバーがいずれかの xml_stuff インスタンスの前に構築されたためです。プレーンな静的データ メンバーを使用すると、C++ では翻訳単位全体の作成順序が定義されていないため、これを保証することはできません。
テスト容易性を考慮し、ファイルを読み取る以外に静的変数を設定する別の方法があり、さらにプロセスの実行時間全体にわたって変更されていないデータに依存しない限り、問題ありません。
コードを設計するときにテストを作成することを考えると、コードを適切に分解して再利用可能に保つのに役立つことがわかりました。