2011-04-15 8 views
4

をコピーします。コピー、エリジョンまたは右辺の参照と移動コンストラクタを避けるために使用されるものは何ですか?以下のコードで、Elisionと右辺の参照

std::string get(){return "...";} 

void foo(std::string var){} 

foo(get()); //<--- here 

答えて

9
std::string get(){ 
    // this is similar to return std::string("..."), which is 
    // copied/moved into the return value object. 
    return "..."; 
} 

RVOは、それが直接get()の戻り値オブジェクトに一時的な文字列オブジェクトを作成することができます。

foo(get()); 

RVOは、それが直接に直接fooのパラメータオブジェクトに一時的な文字列オブジェクト(戻り値オブジェクト)を構築することを可能にします。

これらは、許可されたRVOシナリオです。コンパイラが適用できない場合は、にはがあり、戻り値を戻り値オブジェクトとパラメータオブジェクトにそれぞれ移動するには、移動コンストラクタ(使用可能な場合)を使用します。この場合、両方の一時的なオブジェクトはいずれにしてもrvaluesとして扱われるため、驚くことではありません。 (最初のシナリオでは、式は作成された一時的なものに対応しないため、処理は、一時的な値を戻り値オブジェクトにコピー/移動するために使用されるコンストラクタを選択する目的にのみ使用されます)。他の例については

、コンパイラは右辺値として物事を考慮しなければならない、彼らはそれ以外の場合は左辺値

std::string get(){ 
    std::string s = "..."; 
    // this is similar to return move(s) 
    return s; 
} 

ていてもスペックは、それが潜在的にそれが設定したルールによって、左辺値にRVO(またはNRVO)を適用することができたときに言います式は右辺値として扱う必要があり、利用可能な場合は移動コンストラクタを使用する必要があり、適切なコンストラクタが見つからない場合にのみ、左辺値として式を使用する必要があります。プログラマが明示的な動きを書くのは残念です。プログラマが常にコピーの代わりに動きを望むのは明らかです。

例:最初のため

struct A { A(); A(A&); }; 
struct B { B(); B(B&&); }; 

A f() { A a; return a; } 
B f() { B b; return b; } 

、それは右辺値としてaがかかりますが、(A&は右辺値にバインドできない)この右辺値を受け入れるコンストラクタを見つけることができません。そのため、それは再びaをそのまま(左辺)として扱います。 2番目の場合は、値としてbが入り、B(B&&)はその値を取ります。 Bに暗黙的に宣言されたコピーコンストラクタがないので、bを左辺値(これは何であるか)とみなすと、コピー初期化は失敗します。


戻ってPARAMTER通過は従って

u -> T (where u's type is different from T) => 
    T rvalue_tmp = u; 
    T target(rvalue_tmp); 

t -> T (where t's type is T) => 
    T target = t; 

を意味コピー初期化のルールを使用して、我々は"..."を返す例では、第1の一時右辺値を作成し、それを移動することを注意ターゲットに戻り値/パラメータの型の式を返す場合は、式を直接ターゲットに移動/コピーします。

1

実装定義されていますが、最も可能性の高いコピーの省略。

同様に、RVO/NRVOは、関数からオブジェクト値を返すときに移動セマンティクスに入る可能性が高くなります。

2

ほとんどの場合、ellisionをコピーしますが、コンパイラがこのケースでは適用できない場合は、関数がより複雑な場合に発生する可能性があります。移動は非常に効率的ですので、ellisionが実行されない場合はここではパニックにはなりません。

関連する問題