0

これは奇妙な質問のように思えるかもしれません。現在、特定のオブジェクトを2ステップから1ステップの初期化スキームに移動しています。基本的に、.initialize() .terminate()メンバー関数で行われたことをコンストラクタとデストラクタに移動します。

私の問題は、これらのクラスが外部要因に依存する特定の属性を正しく初期化したかどうかを知ることが重要であるということです。

例として、WinAPIウィンドウを作成するWindowクラスがあります。以前は2ステップのメソッドを使用してinitialize()いたので、ウィンドウが適切に作成されたかどうかのブール値を返していました。

if(myWindow.initialize())
{
    // proceed with application
}
else
{
    // exit
}    

とにかく、コンストラクターからこの情報を中継するために、次のような2番目のメソッドを作成して呼び出す必要はありdidMyWindowInitializeCorrectly()ませんか?

最初、私はの線に沿って何かを望んでいました

if(Window *myWindow = new Window)
{
    // proceed with application
}
else
{
    // exit
}

ただし、ウィンドウの作成に失敗してもWindowオブジェクトはインスタンス化されるため、これは機能しません。

コンストラクターに例外をスローさせ、それをキャッチして続行させる唯一の解決策はありますか?私は多くのスレッドを見てきましたが、C ++の例外に関する人々の意見はかなり分かれているように思われるので、最善のアプローチが何であるかわかりません。

ifステートメントでこの状況を処理する方法はありますか?

4

4 に答える 4

5

これは、例外またはエラーコードベースの初期化の大きな議論に帰着します。コードの後半で is_valid チェックを介して問題が処理されなかったり、2 段階の戻り値を無視したりすると、スタック トレースの早い段階で問題がより明らかになるため、通常はコンストラクターの失敗を示す例外を好みます。また、エラー コードの参照を必要とせずに初期化が失敗した理由についても明確です。例外スタイルの障害メッセージよりも従来の C スタイルを好む人は、最後の点についてはおそらく私の意見に同意しないでしょう。

ただし、多くの場合、コード ベースの残りのスタイルと一致させることをお勧めします。そのため、例外がコード内の他の場所で使用されていない場合は、オブジェクト検証のメカニズムを導入するよりも、is_valid チェック (または元の 2 段階の初期化) を行う方がよいでしょう。Riateche が投稿したように、2 段階よりも is_valid を好みます。これにより、オブジェクトを合法的に使用する前に呼び出す必要がある関数を検索する必要なく、有効であることを確認するかどうか/いつ確認するかをユーザーが選択できるようになります。

于 2012-07-20T23:27:29.237 に答える
2

できることの 1 つは、2 段階の初期化を行う静的メソッドを作成することです。

class Window {
  public:
     static Window* createWindow() {
          Window* w = new Window();
          if (w->isValid()) {
            return w;
          }
          delete w;
          return NULL;
     }
  private:
    Window();
    bool isValid();

};

このようにして、2 段階の初期化を一方向の初期化にカプセル化します。

于 2012-07-21T16:04:23.383 に答える
1

この場合、例外を使用しても問題ありません。通常、コンストラクターは常に有効なオブジェクトを返すか、例外をスローする必要があります。

あなたが本当に例外に反対しているなら、私はあなたのためにこのフォームを提案します:

Window my_window;
if (!my_window.is_valid()) {
  cout << "fail";
  return;
}

ただし、別のinitialize方法の方が適しています。

于 2012-07-20T23:14:52.683 に答える
1

私は確かに例外を使用しますが、何らかの理由で必要ない場合は、 new 演算子をオーバーライドして、エラーが発生した場合に NULL を返すことができます。(記憶を解放することを忘れないでください)戻る前に。

void* T::operator new(size_t x);

編集: 追加するのを忘れました。new をオーバーロードする場合は、malloc とオーバーロード delete でメモリを予約する必要があります。

于 2012-07-20T23:17:42.387 に答える