5

これが私の問題です。struct入力として受け取り、新しいものを割り当ててstructから返す関数があります。にはstruct次の内容があります

struct Data {
std::vector<custom_type> vector_vars;
std::string key;
std::map<std::string, Data*> index;
};

vector_varsサイズは500~1000です。custom_type 関連する場合は、このクラスです。は、別の構造体 by にアクセスするのindexに役立ちます。これが関数です。Datakey

Data func(Data inputData) {

 Data outputData;
//compare values with inputData
//change some values in Data struct
 return outputData
}
  1. スタック割り当てを使用して、RHS にコピーされるように戻しますか。コピーすると多くのオーバーヘッドが発生する可能性があるため、これは賢明ですか?

  2. 関数内のスタックに割り当てられた構造体への参照/ポインターを返すことはできますか?

  3. std::shared_ptr効率のために、代わりに動的割り当てを使用することをお勧めしますか ( を使用することもできます)。

4

4 に答える 4

14
  1. オブジェクトを値で返します。コピーの省略は、標準でコンパイラーが作成できる最適化であり、不要なコピーを削除します。C ++ 03では、コピーはほぼ確実にコンパイラによって削除されます。C ++ 11では、コピーは最初に移動と見なされ(次に、その内容が移動されます)、それでも省略される場合があります。

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

    具体的には、この基準がコピーの省略をもたらす場合、それは一般に名前付き戻り値最適化、つまり戻り値最適化の形式として知られています

    したがって、ここで最も慣用的でパフォーマンスに優しいオプションは、値で返すことです。もちろん、最適化の下でも値による戻りが問題であると測定した場合は、確かに、動的に割り当てることを検討できます(ポイント3を参照)。

  2. いいえ、ローカル変数への参照またはポインタを返さないでください。自動保存期間(スタックに割り当てると呼ぶもの)を持つオブジェクトは、もう存在しません。参照またはポインタはぶら下がったままになります。意味のある方法で使用すると、未定義の動作が発生します。

  3. いいえ、前述のように、値で返すことをお勧めします。ただし、本当に必要な場合は、動的に割り当ててData、スマートポインタで返すことができます。ここで推奨されるスマートポインタはstd::unique_ptr、関数が所有権を呼び出し元の関数に渡しているためです(所有権を共有していません)。

于 2013-03-01T16:06:58.880 に答える
2
  1. 実際、ここでは2つの高速操作のいずれかが発生する可能性outputDataがあります。戻り値に移動するか、この移動を省略できます。どちらの場合も、高価なコピーはありません。のコピーはinputData不要のようです。おそらく、として渡す必要がありますData const& inputData
  2. これを行うことはできますが、未定義の動作が発生します。
  3. いいえ。動的割り当ては、安全性が低く、遅く、混乱を招き、一般的に悪化する可能性があります。
于 2013-03-01T16:06:41.407 に答える
2
Data func1(Data inputData) {
    Data outputData;
    return outputData
}

type のオブジェクトをData値で受け取り、別のインスタンスを作成し、その別のインスタンスをData値で返します。そのため、コピーはoutputDataが返されたときだけでなく、 がinputData受信されたときにも作成されます。値を返す際のパフォーマンスについて心配する必要はありません。それを処理するメカニズムがあります (コピー省略と可能な戻り値の最適化について言及する価値があります)。inputDataただし、参照することをお勧めしますData func1(const Data& inputData)

コピーすると多くのオーバーヘッドが発生する可能性があるため、これは賢明ですか?

経験則: パフォーマンスの問題に直面しない限り、コードのパフォーマンスについて心配する必要はありません。

関数内のスタックに割り当てられた構造体への参照/ポインターを返すことはできますか?

その関数のスコープ内で定義された自動保存期間を持つオブジェクトへの参照/ポインターを返さないでください。実行がスコープ外になると、オブジェクトは破棄されるため、未定義の動作につながるダングリング ポインター(無効な参照) が発生します。

効率のために、代わりに動的割り当てを使用することをお勧めしますか?

可能な限り動的割り当てを避けてください。効率のためではなく、コード内のメモリ管理のためです。RAII のイディオムに従い、醜いメモリ管理を自分で処理することは避けてください。

于 2013-03-01T16:12:36.723 に答える
1

a の代わりにfunc()return a を取るように書き直すことができます。確かに、 a をコピーするよりも a をコピーする方がはるかに高速です。しかしその前に:気にしますか?この関数は、プログラムの初期化中に 1 回実行され、ウォール クロック時間の 10 分の 1 秒かかりますか、それとも 1 フレームに 1 回呼び出されると予想されますか、それとも何ですか?Data*DataData*Data

プログラムを作成したり、既存のプログラムを最適化したりするときの目標は、常にそれを「十分に速く」(そして「十分に応答性を高く」) することですが、今のところ気にしないでください)。「十分な速さ」の定義はさまざまです。シミュレーションでは 1 時間あたり 1 テラバイトのデータを高速処理できますが、ビデオ ゲームでは 16 ミリ秒ごとに新しいグラフィックス フレームをプレーヤーに表示する必要があります。

だから:あなたのプログラムはスタック割り当てだけで「十分に速い」ですか?もしそうなら、放っておいてください。そうでない場合は、代わりに動的割り当てを使用してください。一般に、大きな構造体の代わりにポインターを返すことは C++ スタイルとしては適切ですが、まだ学習している間はそれについて心配する必要はありません。機能させ、正しくし、高速化します。

于 2013-03-01T21:47:24.087 に答える