初期化メソッドを避ける


12

この既存のコードには、クラスとそのクラスの初期化メソッドがあります。クラスのオブジェクトが作成されたら、そのオブジェクトでinitializeを呼び出す必要があります。

初期化メソッドが存在する理由 オブジェクトは、グローバルスコープを持つように早期に作成され、その後、依存するDLLを読み込んだ後に初期化メソッドが呼び出されます。

初期化 の問題クラスには現在、このbool isInitializedがあります。初期化されていない場合、処理を続行してエラーを返す前にすべてのメソッドでチェックする必要があります。簡単に言えば、それは大きな痛みです。

考えられる解決策の1つ は、コンストラクターで初期化することです。グローバルスコープ内のオブジェクトへのポインターのみがあります。dllがロードされた後、実際のオブジェクトを作成します。

上記のソリューションの問題 このクラスのオブジェクトを作成する人は誰でも、dllがロードされた後にのみ作成される必要があることを知る必要があります。さもないと、失敗します。

これは受け入れられますか?


私は、OpenGLコンテキストが存在する前に、必要がインスタンス化することのOpenGL関連オブジェクトを作成するときに、この同じ問題を持っていた、しかしなどcalllists、テクスチャ、などのOpenGLの依存オブジェクトを保持することになっている

3
愚かな質問#1:オブジェクトコンストラクターがDLLをまだロードしていないのにロードできないのはなぜですか?
ジョンR.ストローム

1
古い質問を復活させて申し訳ありませんが、2017年に誰かがこれを読んでいる場合は、C ++ 11使用call_onceしてください。まだC ++ 11になっていないプロジェクトは、call_onceがC ++ 11でどのように実装されるか(どの問題を解決するか、どのように解決するか)を研究し、C ++の(古い)フレーバーで再実装する必要があります。状態を静的に(定数値で)初期化する必要があるマルチスレッド対応の同期プリミティブが必要です。C ++ 11より前のコンパイラには、満たす必要がある他の特異性がある可能性があることに注意してください。
rwong

回答:


7

仮想プロキシの仕事のように聞こえます。

問題のオブジェクトへの参照を含む仮想プロキシを作成できます。DLLがロードされていない間、プロキシは特定のデフォルトの動作をクライアントに提供できます。DLLがロードされると、プロキシはすべてのリクエストを実際のサブジェクトに単に転送します。

仮想プロキシは、DLLの初期化を確認し、これに基づいて、要求を実際のサブジェクトに委任するかどうかを決定します。

ウィキペディアのプロキシパターン

このアイデアはどうですか?


ここではあまり解決できません。実際のオブジェクトに追加されたすべてのメソッドについて、そのメソッドもプロキシに追加する必要があります。番号?

これにより、initを呼び出すことを忘れないでください。関数ですが、プロキシ内のすべての関数が.dllがロードされているかどうかを確認する必要があるようです。

1
@Sriramには大きな違いがあります。プロキシを使用すると、DLLチェックに関連するメンテナンスを単一クラスのプロキシに制限します。クラスのクライアントは、DLLチェックについてまったく知る必要さえありません。ほとんどのメソッドは委任を行うので、プロキシの実際のサブジェクトの両方にインターフェイスを実装する必要がある場合、問題はあまりありません。つまり、DLLがロードされたことを確認するまで、実際のサブジェクトの作成を防ぐことができます。そうすれば、毎回DLLの状態を確認する必要がなくなります。

@edalorzo:アイデアは良いですが、ここでの問題は、我々はすでにプロキシについて話している、とOPはそのプロキシの各方法でチェックする必要が文句を言っているということです...
マシューM.

4

DLLがまだロードされていない場合は、何も役に立ちません。オブジェクトはエラーのみを生成します。致命的なエラーですか?エラーはどのように処理されますか?

あなたのテスト方法論は、最終製品でこのエラーが発生しないことを保証していますか?

建築設計のためではなく、テストのための仕事のように思えます。エラーを返さないでくださいassert。エラーは発生しません。

現在エラーをキャッチして無視しているクラスのクライアントを修正し、そもそもエラーが発生しないようにします。

マルチスレッドパターンは、DLLのロード後に共有条件変数を設定し、DLLがロードされるまでオブジェクトのコンストラクターを待機(および他のスレッドをブロック)することです。


DLLが適切に初期化されていない場合、問題のオブジェクトの作成時に例外をスローしても問題はありません。クライアントコードはこの例外を処理するだけでよく、テストでは例外が適切に処理されることを確認する必要があります。

2

最初に、状態が決して変わらない(構成)場合を除き、害虫としてのグローバルオブジェクトを避けます。

今、あなたがそれで立ち往生している場合、何らかの理由で、おそらくあなたを助けることができるいくつかのデザインがあります。

私は2つのアイデアを思いつきました:

  1. ファサードを使用してDLLをロードします。オブジェクトはFacadeを介してのみアクセスでき、Facadeは作成時にDLLをロードし、同時にオブジェクトをインスタンス化します。

  2. プロキシを使用しますが、スマートな種類;)

@edalorzoの答えがあなたを怖がらせるかもしれないと恐れているので、2番目の点について詳しく説明させてください。

// Private
static Object& GetObjectImpl() { static Object O; return O; }

// Public
static Object& GetObject() {
  Object& o = GetObjectImpl();
  assert(o.isInitialized() && "Object not initialized yet!");
  return o;
}

これで、チェックは1つだけになりました。

これは、何らかのスマートポインターを使用して行うこともできます。

Pointer<Object> o;

ここでは、最初はnullのポインター用のスペースのみを予約し、DLLがロードされたときにのみ実際にオブジェクトを割り当てます。以前のアクセスはすべて、例外を発生させるか(NullException:p?)、プログラムを終了する必要があります(クリーンに)。


1

これは難しい質問です。アーキテクチャが問題の解決に役立つと思います。

証拠から、プログラムのロード時に.dllがロードされていないように聞こえます。プラグインのように聞こえます。

思い浮かぶことの1つは、.dllを初期化する必要があるということです。プログラマーは、とにかくオブジェクトが確実に戻ってくることはないと想定しなければなりません。これを利用できる可能性があります(bool isObjectLoaded() { return isInitialized; })が、チェックよりも多くのバグレポートを確実に取得できます。

私はシングルトンを考えていました。

シングルトンを呼び出す場合、それが取得できる場合は正しいオブジェクトを返す必要があります。正しいオブジェクトを返せない場合は、エラー値/ nullptr /空のベースオブジェクトを取得する必要があります。しかし、オブジェクトがあなたの上で死ぬことができるならば、これは機能しません。

また、オブジェクトの複数のインスタンスが必要な場合は、代わりにFactoryのようなものを使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.