3

戻り値の型としてオブジェクト型を持つメンバー関数があります。

MyObject myfunction(parameters) {
    if (some condition) { 
        return MyObject(parameters);
    } else { 
        ... no valid object can be created ... 
    } 
}

特定の条件下(関数本体でチェックされている)では、タイプMyObjectのオブジェクトを作成して返すことはできません。

たまにC++プログラマーになるだけで、私は自発的に3つの解決策を思いつくことができます。

  1. 戻り値の型を*MyObjectに変更し、有効なオブジェクトを作成できない場合はnullptrを返し(C ++ 11)、呼び出し元のコードでnullptrと等しいかどうかを確認します。
  2. オブジェクトを作成できない場合に例外をスローし、呼び出し元のコードでそのオブジェクトをキャッチします。
  3. 無効と定義したいくつかの値を使用してオブジェクトを作成し、返されたオブジェクトを使用する前にそれを確認します。

このような状況に対処するための標準的な方法と、パフォーマンスの観点からの最善の解決策は何でしょうか。...または私が見ないいくつかの明らかな回避策...

最先端のC++11ソリューションが最適です:-)

これまでの私の考え:
ソリューション1は問題ないようですが、C ++ 11のみであり、メインプログラムに渡す(オブジェクト自体を呼び出し元の関数に返す)には、返されたオブジェクトをヒープ上に作成する必要があります。 、したがって、スタックに保持する方が小さなオブジェクトの方が速いかもしれませんか?)
解決策2は遅くなる可能性があり、メインプログラムでの冗長なコーディングにつながります。
解決策3はおそらく最も遅く(オブジェクトが無駄に作成される)、メインプログラムでチェックするのにあまり便利ではありません。

私のコードでは、有効な戻りオブジェクトは例外ではなくデフォルトの状況であり、作成されたオブジェクトはかなり小さいですが、さまざまなケースを考慮した一般的な考慮事項は、他の読者のアプリケーションにとって確かに役立ちます...

助けてくれてありがとう:-)

4

4 に答える 4

7

通常の場合、Boost.Optionalを返すことは機能します:

boost::optional<MyObject> myfunction(parameters) {
    if (some condition) { 
        return MyObject(parameters);
    } else { 
        return boost::none;
    } 
}

そして、コールサイトで:

auto ret = myfunction(...);
if(ret)
  // use '*ret'  or 'ret.get()'

しかし、R。Martinhoが述べているように、このソリューションには欠点があります(つまり、Boost.Optionalはmove-semanticsをサポートするようにまだ更新されていないため、move-onlyタイプは機能しません)。

于 2012-10-26T14:17:56.803 に答える
4

あなたの質問は一般的に表現されているので、私も一般的に答えます。

オブジェクトを作成して返すことが仕事である関数がある場合、それ仕事です。

ここで、オブジェクトの構築に必要な証明書の条件が満たされない場合にオブジェクトを返さないようにこの関数を設計する場合は、実際にこの関数のセマンティクスを変更しています。代わりに、1つの責任だけで、3つあります。

  1. オブジェクトを構築するための適切な条件が存在するかどうかを判断します
  2. はいの場合、オブジェクトを作成して返します
  3. いいえの場合、何も返さないか、作成されていないことを示す条件値を返します

単一責任の原則」は、一般に、優れた設計では、1つの機能(またはクラスまたはあなたが持っているもの)が1つの仕事をする必要があることを示しています。ここで、関数には3つあります。

私はあなたの提案されたアプローチのどれも一般的に最善ではないことを提案します。むしろ、私は一緒に行きます:

4:オブジェクトを構築するための適格性を判断するために、別の関数を実装します。その関数がtrueを返す場合は myFunction、オブジェクトを作成して返す呼び出しを呼び出します。

于 2012-10-26T14:23:19.663 に答える
4

状況に応じて、提案された3つのソリューションすべてが有効で一般的です。

オブジェクトを作成できないことがエラー状態であり、呼び出し元の関数が中止、バックアップ、再試行、またはその他の抜本的な対策を講じる必要がある場合は、例外をスローします。

オブジェクトを作成できないことが日常的なイベントであり、呼び出し元がオブジェクトが作成されたかどうかを確認し、どちらの場合もかなり正常に続行することが期待される場合は、nullを返すことをお勧めします。

作成できる妥当なダミーまたは空白のオブジェクトがある場合、それは良い解決策です。しかし、これは非常にまれです。これは、呼び出し元が実際にダミーオブジェクトを処理する場合にのみ行う必要があります。

nullポインターを返すと、この関数を呼び出すすべての場所で作成していることがわかります。

MyObject* myobject=myfunction(whatever);
if (myobject==null) throw new PanicException;

次に、関数内で例外をスローすることもできます。

さらに悪いことに、あなたが書いているなら:

MyObject* myobject=myfunction(whatever);
if (myobject!=null)
{
  ... process it ...
}
else
{
   ... display error message ...
}

次に、IFステートメントを使用して例外処理をシミュレートしているだけです。実際の例外を使用します。

一方、例外をスローした後、定期的に次のように書いていることに気付いた場合:

MyObject* myobject;
try
{
  myobject=myfunction(whatever);
}
catch (PanicException pe)
{
  myobject=null;
}

それなら、nullを返すだけの方がいいでしょう。

時々ダミーオブジェクトを作成しました。最も一般的なケースは、関数が配列やリンクリストなどのコレクションを返し、コレクションに入れるデータが見つからない場合は、要素がゼロのコレクションを返す場合です。次に、呼び出し元はコレクション内の要素をループします。要素がない場合は、問題ありません。名前や顧客IDなどの長さがゼロの文字列を持つオブジェクトを返したケースがいくつかあります。ただし、一般に、呼び出し元がテストしてダミーオブジェクトであると言うことができるようにダミーオブジェクトを返すだけの場合は、nullを返す方がよいと思います。

ところで、C++11ではnullポインタしか返すことができないと言ったときに何を意味するのかわかりません。nullを渡す機能は、私が今まで見た中で最も初期のバージョンのC++に戻ります。

于 2012-10-26T14:31:44.880 に答える
2

オブジェクトの作成を妨げる条件が例外的である場合を除いて、最初の解決策を使用する必要があります。それ以外の場合、NULLポインターを返すことは、C++11でも完全に有効な解決策です。

もちろん、「ポインタ」はstd::unique_ptrなどのRAIIコンテナを使用してラップする必要があります。本当にあなたのコードの一般的な習慣であるはずです。

3番目の解決策は、私に言わせれば、リソースを完全に浪費することです。無効な(役に立たない)オブジェクトを作成し、それをコピーして戻り値にする必要があります...破棄する場合のみです。

于 2012-10-26T14:17:44.103 に答える