5

大きなベクトルを設定する関数の戻り値として auto_ptr を使用すると、関数がソース関数になります (内部の auto_ptr が作成され、const 以外の auto_ptr を返すときに所有権が渡されます)。ただし、データにアクセスするには auto_ptr を逆参照する必要があるため、この関数を STL アルゴリズムで使用することはできません。私が推測する良い例は、各ベクトルが 100 個のコンポーネントを持つサイズ N のベクトルのフィールドでしょう。N が大きい場合、関数が各 100 成分ベクトルを値または ref で返すかどうかは同じではありません。

また、この非常に基本的なコードを試すと、次のようになります。

class t
{
    public: 
         t() { std::cout << "ctor" << std::endl; }
         ~t() { std::cout << "dtor" << std::endl; }
};

t valueFun()
{
   return t();
}

std::auto_ptr<t> autoFun()
{
   return std::auto_ptr(new t());
}

autoFun と fun 呼び出しの両方が出力されます

Ctor Dtor

そのため、return ステートメントに渡されるように作成されている自動変数を実際に見ることはできません。これは、valueFun 呼び出しに対して戻り値の最適化が設定されているということですか? この場合、valueFun は 2 つの自動オブジェクトを作成しますか?

このような大規模なデータ構造の母集団を関数で最適化するにはどうすればよいでしょうか?

4

2 に答える 2

4

これには多くのオプションがあり、動的割り当てが最適ではない場合があります。


この議論を掘り下げる前に、これはボトルネックですか?

プロファイリングせず、それがボトルネックであることを確認した場合、この議論は完全にオフになる可能性があります...デバッグビルドのプロファイリングはほとんど役に立たないことを覚えておいてください。


現在、C++03 には、最も口当たりの良いものから最低のものまで、いくつかのオプションがあります。

  • コンパイラを信頼してください。たとえば、名前のない変数は、gcc のデバッグ ビルドでも RVO を使用します。
  • 「out」パラメーターを使用する (参照渡し)
  • ヒープに割り当て、ポインターを返します (スマートかどうかに関係なく)
  • コンパイラの出力を確認してください

個人的には、プロファイラーが私が間違っていることを証明しない限り、これについてはコンパイラーを信頼します。

C++11 では、ムーブ セマンティクスにより自信を深めることができます。これは、returnステートメントがあるときはいつでも、RVO が開始できない場合、ムーブ コンストラクター (利用可能な場合) を自動的に使用できるためです。コンストラクターを移動するのvectorは非常に安価です。

したがって、次のようになります。

  • コンパイラを信頼する: RVO または移動セマンティクスのいずれか
  • ヒープに割り当て、unique_ptr

しかし、実際には 2 番目の点は、ムーブ セマンティクスがあまり役に立たないいくつかのクラスにのみ使用する必要があります。ムーブ セマンティクスのコストは、通常、 の戻り値に比例しsizeofますstd::array<T,10>10*sizeof(T)ヒープ割り当て + からunique_ptr


Tangent: あなたは既にコンパイラを信頼しています。エラーについて警告することを信頼し、危険な/おそらく正しくない構成について警告することを信頼し、コードを機械アセンブリに正しく変換することを信頼し、意味のある最適化を適用して適切なスピードアップを実現することを信頼します.明らかな場合に RVO を適用するコンパイラを信頼しないことは、10 ドルの請求書で心臓外科医を信頼しないようなものです。;)

于 2012-05-04T14:46:00.250 に答える
1

コンパイラーが valueFun の戻り値の最適化を行うと確信しています。コンパイラが戻り値の最適化を適用できない主なケースは次のとおりです。

  • パラメータを返す
  • 条件に基づいて別のオブジェクトを返す

したがって、auto_ptr は必要なく、ヒープを使用する必要があるためさらに遅くなります。

このような大きなベクトルを移動するコストについてまだ心配している場合はstd::vector aCopy(std::move(otherVector))、C++ 11 の移動セマンティクスの使用を検討することをお勧めします。これらは RVO とほぼ同じくらい高速で、どこでも使用できます (また、 RVO が使用できない場合の戻り値に使用されることが保証されています。)

この時点で、ほとんどの最新のコンパイラは移動セマンティクス (または技術的に右辺値参照) をサポートしていると思います

于 2012-05-04T13:46:35.923 に答える