無名のオブジェクトのRVO(返品値の最適化)は普遍的に保証された動作ですか?

StackOverflow https://stackoverflow.com/questions/8410877

質問

この質問 異なる面で(GCCにも限定されています)。私の質問はのためだけのものです 名前のないオブジェクト. 返品値の最適化 変更が許可されています 観察可能な動作 結果のプログラムの。これは標準でも言及されているようです。

しかし、これ "に許可された" 用語は混乱しています。それはRVOを意味しますか 保証されています すべてのコンパイラで発生する。コードの変更以下のRVOにより、観察可能な動作があります。

#include<iostream>
int global = 0;
struct A {
  A(int *p) {}
  A(const A &obj) { ++ global; }
};

A foo () {  return A(0); }  // <--- RVO happens
int main () {
  A obj = foo(); 
  std::cout<<"global = "<<global<<"\n"; // prints 0 instead of 2
}

このプログラムは印刷すると想定していますか global = 0 コンパイラの最適化とメソッドサイズに関係なく、すべての実装について foo ?

役に立ちましたか?

解決

標準によれば、プログラムは0、1、または2を印刷できます。C++ 11の特定の段落は、以下で始まる12.8p31です。

特定の基準が満たされている場合、オブジェクトのコピー/移動コンストラクターおよび/またはデストラクタが副作用を備えていても、クラスオブジェクトのコピー/移動を省略/移動する実装が許可されます。

両方のコピーエリジョンシングは、 かのように ルール(プログラムの動作が同じプログラムの動作と一致する必要があります かのように 最適化は行われていません)。標準により、実装が異なる観察可能な動作を生成できるようにし、プログラムに依存しない(または3つの可能な結果すべてを受け入れる)プログラマーがあなた次第です。

注2:1は答えのいずれにも言及されていませんが、結果の結果です。関数のローカル変数から返されたオブジェクト、オブジェクトまで、2つの潜在的なコピーが行われています main, 、コンパイラは、3つの可能な出力すべてを生成する1つまたは2つのコピーを削除できます。

他のヒント

保証することはできません。そのような保証を首尾一貫して書こうとした場合、そうすることは不可能だと思うでしょう。

たとえば、このコードを検討してください。

std::string f() {
  std::string first("first");
  std::string second("second");
  return FunctionThatIsAlwaysFalse() ? first : second;
}

関数 FunctionThatIsAlwaysFalse 常に戻ります false, 、しかし、モジュール間の最適化を行う場合にのみ伝えることができます。この場合、RVOを使用できるように、すべてのコンパイラがモジュール間最適化を行う必要がありますか?それはどのように機能しますか?または、モジュール間最適化が必要な場合、コンパイラがRVOを使用することを禁止する必要がありますか?それはどのように機能しますか? RVOがそれを行うことから可能であることを確認するのに十分賢いコンパイラーと、それをしないことからではないことをどのように止めることができますか?

すべての最適化コンパイラがRVOでサポートするために必要な標準リストは?そして、それは他の場合にRVOを禁止すべきですか?コンパイラを最適化するポイントを倒すのではないでしょうか?

そして、コンパイラがRVOがパフォーマンスを低下させると信じているケースはどうですか?コンパイラは、悪いと思われる最適化を行う必要がありますか?例えば:

if(FunctionCompilerKnowsHasNoSideEffectsAndThinksMostlyReturnsFalse())
  return F(3); // Here RVO is a pessimization
else
{
 Foo j=F(3);
 return Foo(j);
}

ここで、コンパイラがRTOを実行する必要がない場合、 if 関数呼び出しは、RTOがないため、コードは両方の半分で同じです。コンパイラに、事態が悪化すると考えている最適化を強制する必要がありますか?なんで?

そのような保証を機能させる方法は本当にありません。

ペダントで言えば、その実装は定義されています。モダンなコンパイラは、このような種類の最適化を行うのに十分なインテリジェントです。

しかし、動作が実装間でまったく同じであるという保証はありません。それが何なのか 実装が定義されています 行動はすべてです。

この文脈で「許可される」はそれを意味します 0 また 1 また 2 標準的な適合出力です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top