0

私は C++ の初心者で、ローカル変数を返す 3 つの方法を知っていますが、すべてに欠点があります。

Person& getPerson()
{
   Person bob;
   return bob;
}

明らかに良い考えではありません。

Person getPerson()
{
   Person bob;
   return bob;
}

null ポインターやダングリング参照の可能性はありませんが、パフォーマンスが低下します。

Person* getPerson()
{
   return new Person();
}

null ポインターの可能性はありませんが、これは OO 設計の基本的な規則に違反していることは確かです。別のオブジェクトがこれを削除する必要がありますが、なぜ削除する必要があるのでしょうか? getPerson() メソッドの実装は、それとは何の関係もありません。

だから、私は代替手段を探しています。共有ポインターとスマート ポインター (標準およびブースト) について聞いたことがありますが、それらのいずれかがこの問題に対処するように設計されているかどうかはわかりません。あなたたちは何を提案しますか?

4

7 に答える 7

6

オプション #2: 値で返す。

Person getPerson()
{
  Person bob;
  return bob;
}

ここではパフォーマンスへの影響はありません。このコピーは、コンパイラによって省略される可能性があります (おそらく省略される可能性があります)。実際、コンパイラのコピー省略最適化をオフにしても、C++11 コンパイラではこれが最初の移動と見なされます。

実際、Person p = getPerson()通常は 2 つのコピーが含まれる を行ったとしても、両方が省略される可能性があります。

§12.9/31 を参照:

クラスの戻り値の型を持つ関数のreturnステートメントで、式が関数の戻り値の型と同じ cv-unqualified 型を持つ不揮発性自動オブジェクト (関数または catch-clause パラメーター以外) の名前である場合、自動オブジェクトを関数の戻り値に直接構築することにより、コピー/移動操作を省略できます

そして§12.9/32:

コピー操作の省略の基準が満たされているか、ソース オブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値によって指定されているという事実を除いて満たされる場合、コピーのコンストラクターを選択するためのオーバーロードの解決は次のとおりです。オブジェクトが右辺値によって指定されたかのように最初に実行されます。

于 2013-02-26T20:46:20.390 に答える
4

null ポインターやダングリング参照の可能性はありませんが、パフォーマンスが低下します。

実際、パフォーマンスはまったくヒットしませんでした。ここで例を参照してください:スピードが欲しいですか? 値渡し

コンパイラは、コピー省略と呼ばれる戦略と名前付きの戻り値の最適化を使用して、それを簡単に最適化できます(そのリンクを確認してください)。

于 2013-02-26T20:45:50.743 に答える
3

ここでは、パフォーマンスへの影響についてあまり心配する必要はありません。

Person getPerson()
{
   Person bob;
   return bob;
}

あなたが心配しているコピーは、おそらく戻り値の最適化 (RVO)と呼ばれるもので省略されます。C++ 標準では、as-ifルールに違反していても、コンパイラはこの最適化を行うことができます。この種の式でコピーを省略しないコンパイラに長い間出会っていません。

Person p = getPerson();

C++11 では、コピー省略がない場合でも、これはムーブ構築の候補になります。これ非常に安価な操作になる可能性がありますが、それは問題のタイプによって異なります。いずれにせよ、コピーの省略は避けるのが難しいです。

この関連記事を参照してください。

このデモを参照してください。

于 2013-02-26T20:46:08.973 に答える
2

他の人がすでに指摘しているように、戻り値の最適化は、単純に値を返すことによるパフォーマンスへの影響を最小限に抑えるのに役立ちます。

移動セマンティクス (C++11 の新機能) もこの点で役立ちます。戻り式は "xvalue" の標準的な例であり、その値を移動元から移動先に移動するのに適しています。コピーしました。特に、ほとんどが実際のデータへのポインターで構成されるタイプ (ベクターなど) の場合、これは本質的に深いコピーではなく浅いコピーを可能にするため (つまり、ベクター全体のコピーを作成する代わりに)、非常に有益です。 、ポインターをコピーするだけです)。

ここでも shared_ptr または unique_ptr を使用できます。shared_ptr は基本的に参照カウント ポインターであるため、(C++11 より前のバージョンでは) リターン プロセス中に参照カウントをインクリメントし、その後再びデクリメントするだけで、オブジェクトを存続させることができます。少なくともシングル スレッド環境では、これは一般にかなり安価です。多くの場合、データのコピーを作成するよりも安価です。

unique_ptr はほぼ同様のことを行いますが、参照カウントをインクリメントおよびデクリメントするオーバーヘッドはありません。基本的な違いは、コピーを安価にする代わりに、ポインターを移動してコピーをまったく行わないようにすることです。

これらのいずれも機能しますが、ほとんどの場合、値を返すだけが最も優れていることは明らかです (そして、それが理にかなっている場合は、使用している型にムーブ コンストラクターやムーブ代入演算子を追加します)。

于 2013-02-26T20:57:02.627 に答える
0

ポリモーフィック オブジェクトを返す必要がある場合は、一意のポインターを使用することをお勧めします。

std::unique_ptr<Person> getPerson()
{
    return std::unique_ptr<Person>(new Programmer);
}
于 2013-02-26T21:23:52.723 に答える
0

私はこれについてたくさんのことを知っています。

もう 1 つの方法は、何も返さないことです。

オブジェクトに何をすべきかを伝えます:

  • このレンダラーを使用して、自分自身を表示します
  • このシリアライザーを使用して自分自身をシリアライズします (実装は xml、データベース、json、ネットワークの可能性があります)
  • 今回の状態を更新します
  • このコントロール クリエーターを使用して、コントロールで自分を装飾します (スライダー、ドロップダウン リスト、チェックボックスなどを作成します)。

全体的にゲッターは必要ありません。それらを回避する努力をすれば、あなたのデザインが快適に変更され、テスト可能で合理的であることがわかるでしょう。

于 2013-02-26T22:02:07.437 に答える
0

関数の実行が完了すると、ローカル変数はスコープ外になります - それらの有効期間は終了します - 。したがって、一般に、ローカル変数への参照またはポインターを返すことはお勧めできません。

やりたいことは、クラス オブジェクトがスコープ内にあるか有効な有効期間がある限り、有効期間を維持するクラス メンバー変数への参照またはポインターを返すことです。

于 2013-02-26T20:49:36.920 に答える