1

次のコードを見てください。

class MyClass{
public:
    MyClass(){}
    MyClass(MyClass &&){}
    MyClass(const MyClass &){}
};
MyClass f1(){
    MyClass &&o=MyClass();
    /*...*/
    return std::move(o);//or return static_cast<MyClass &&>(o);
}
MyClass f2(){
    MyClass o=MyClass();
    /*...*/
    return o;
}


int main(int, char **){
    auto a=f1();
    auto b=f2();
}

関数f2は、オブジェクトを返す通常の形式です。NRVOが適用される可能性があり、追加のコピーコンストラクター呼び出しを回避できます。f1右辺値参照を使用する新しいフォームです。NRVOをサポートしていないが右辺値参照をサポートしているシステムの場合、コピーコンストラクターではなく、移動コンストラクターが呼び出されます。これは、ほとんどの場合に適していると見なされます。

問題はf1次のとおりです。この場合、NRVOをサポートするコンパイラはありますか?やっぱり将来的にはもっといい形になりそうです。

4

2 に答える 2

4

この場合、NRVO のコンパイラ サポートはありますか?

「コンパイラサポート」を定義しますか?

のコピーを最適化するコンパイラの機能を完全に破壊f1します。詳しく見てみましょうMyClassf1

MyClass &&o=MyClass();

これにより、スタック変数ではなく、一時的なが作成されます。次に、そのテンポラリは と呼ばれる右辺値参照にバインドされますo。これにより、テンポラリの有効期間が関数の最後まで延長されます。

return std::move(o); //or return static_cast<MyClass &&>(o);

これは、スタック バインドされた右辺値参照の右辺値参照を一時に返します。また、参照ではなく値を返すため、コンパイラはそれから一時的なものを作成する必要があります。

一時的なへのコピー/移動はa省略されます。ただし、まだ2 つの一時 (元の値と戻り値) を作成しています。

以下f1も同様です。

create temporary
copy/move from temporary to return value
elide copy/move from return value to `a`.

f2する:

create stack variable
elide copy/move from stack variable to `b`.

NVRO が存在しない場合は、次のようになります。

create stack variable
copy/move from stack variable to return value
elide copy/move from stack variable to `b`.

したがって、f2最悪でも に等しくなりf1ます。そして、おそらく、より良いです。

コンパイラを考え抜くのはやめてください。コピー省略にその仕事をさせてください。

于 2011-10-26T04:02:03.073 に答える
2

これは、現在のコンパイラ (MSVC10 / gcc トランク) のしくみです:
MyClass が移動可能であると仮定 します

f1 : move   
f2 :   
worst case : move 
best case : NRVO 

MyClass が移動可能ではないと仮定します:

f1 : copy    
f2 :    
worst case : copy    
best case : NRVO 

したがって、コンパイラが改善され、f1 のような関数に対して NRVO を実行し始めたとしても、f2 の古典的な C++03 関数が既に最適であるのに、なぜわざわざコードを複雑にするのでしょうか?

于 2011-10-26T09:54:27.567 に答える