9

関数は、呼び出し元に2つの値を返す必要があります。実装するための最良の方法は何ですか?

オプション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);

Option2では、コピー/移動はありませんが、見た目は醜いです。Option1、1.1でコピー/移動は発生しますか?UとVがコピー/移動操作の両方をサポートする巨大なオブジェクトであると仮定しましょう。

Q:標準に従ってRVO / NRVOの最適化を理論的に行うことは可能ですか?はいの場合、gccまたは他のコンパイラはまだ実装されていますか?

4

4 に答える 4

8

戻るときにRVOは発生しstd::pairますか?

はい、できます。

それは起こることが保証されていますか?

いいえそうではありません。


C++11 標準: セクション 12.8/31:

特定の基準が満たされると、オブジェクトのコピー/移動コンストラクターおよび/またはデストラクタに副作用がある場合でも、実装はクラス オブジェクトのコピー/移動構築を省略できます。

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

于 2012-12-26T17:06:40.270 に答える
4

RVO は保証されていませんが、C++11 では、あなたが定義した関数は少なくともムーブリターンしなければならないと私は信じています。それらを使用するための特定のポリシー)。

また、この例で RVO を使用したとしても、make_pair を明示的に使用すると、常に少なくとも 1 つの余分なペアの構築と移動操作が必要になります。ブレースで初期化された式を返すように変更します。

return { getU(), getV() };
于 2012-12-27T03:07:40.240 に答える
1

RVO または Copy elision はコンパイラに依存するため、RVO を使用して Copy コンストラクターの呼び出しを回避する場合は、ポインターを使用するのが最適なオプションです。

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

あなたの質問に来て、オプション1では、UまたはVを返さずにstd::pairオブジェクトを返すため、UとVのコピーコンストラクターは呼び出されないため、コピーコンストラクターが呼び出され、ほとんどのコンパイラーは間違いなくここでRVOを使用してそれを回避します.

ありがとうニラジ・ラティ

于 2012-12-26T17:14:47.973 に答える