2012-12-26 11 views
7

関数は、呼び出し元に2つの値を返す必要があります。実装する最良の方法は何ですか?std :: pairを返すとRVOが発生しますか?

オプション1:

pair<U,V> myfunc() 
{ 
... 
return make_pair(getU(),getV()); 
} 

pair<U,V> mypair = myfunc(); 

オプション1.1:

// Same defn 
U u; V v; 
tie(u,v) = myfunc(); 

オプション2:

void myfunc(U& u , V& v) 
{ 
u = getU(); v= getV(); 
} 

U u; V v; 
myfunc(u,v); 

私はオプション2を知っているが、何のコピー/移動はありませんが、それは醜いです。 Option1,1.1に何らかのコピー/移動がありますか? UとVは両方のコピー/移動操作をサポートする巨大なオブジェクトであると仮定します。

Q:標準的なRVO/NRVOの最適化は理論的に可能ですか?はいの場合、gccやその他のコンパイラはまだ実装されていますか?

+1

RVO/NRVOを禁止する 'std :: pair'については何も知りません。一般に、コピーがいつ発生するかを示すコピーコンストラクタを含めることで、テストするのはかなり簡単です。 –

+1

g ++はペアのコピーを防止するRVOを実装していますが、ペアにはuとvのコピーがあります。 –

+0

私はいくつかのテストを実行しました.g ++では、どちらが高速化されたかは、インライン化が可能であることと、UとVのコピーコンストラクタの複雑さに大きく依存することがわかりました。パフォーマンスを探しているなら、どちらが最速かを判断するためにプロファイルする必要があります。 –

答えて

8

std::pairを返すとRVOが発生しますか?

はいできます。

これは保証されていますか?

いいえ。


C++ 11標準:セクション12.8/31:特定の基準が満たされ

、実装があっても、クラスオブジェクトのコピー/移動する構成を省略することが許可されていますオブジェクトのコピー/移動コンストラクタおよび/またはデストラクタには副作用があります。

コピーelisionは保証されている機能ではありません。最適化コンパイラはを実行できる場合はいつでも実行できます。。特別なものはありません。std::pair。コンパイラーが最適化の機会を検出するのに十分な場合は、そうするでしょう。したがって、あなたの質問はコンパイラに固有ですが、他のクラスについては同じルールがstd::pairに適用されます。

1

RVOまたはCopy elisionはコンパイラに依存していますので、RVOを使用して、コピーコンストラクタへの呼び出しを避ける場合は、ポインタを使用することをお勧めします。

私たちの製品では、コピーコンストラクタを避けるためにポインタとブーストコンテナポインタを使用しています。これは実際に約10%のパフォーマンス向上をもたらします。

あなたの質問にお答えします オプション1 UとVを返さず、std :: pairオブジェクトを返すので、UとVのコピーコンストラクタは呼び出されませんので、コピーコンストラクタが呼び出され、ほとんどのコンパイラが確実に使用しますここを避けるためにRVO。あなたはそれを定義しているようRVOは、C++ 11の機能では、保証されていないが

おかげ Niraj Rathi

4

私は非常に少なくとも、リターンを移動させなければならないと考えているので、私はむしろ、明確な定義を残すことをお勧め出力変数を受け入れるようにワープするよりも(あなたがそれらを使うための特定の方針を持っていなければ)。

また、この例でRVOを使用していたとしても、明示的にmake_pairを使用すると、少なくとも1つの余分なペア構成があり、したがって移動操作が常に発生します。中括弧で初期化された式を返すように変更してください:

return { getU(), getV() }; 
関連する問題