2012-11-29 12 views
10

このプログラムは、関数の外に列を移動し、別の文字列の構築のためにそれを使用しよう:std :: ::関数からオブジェクトを移動することは可能ですか? (C++ 11)

#include <iostream> 
#include <string> 
#include <utility> 

std::string && Get_String(void); 

int main(){ 

    std::string str{Get_String()}; 
    std::cout << str << std::endl; 

    return 0; 
} 

std::string && Get_String(void){ 

    std::string str{"hello world"}; 

    return std::move(str); 
} 

プログラムはコンパイルが、実行時にセグメンテーション違反します。


これは私の理論的根拠です:Get_Stringは、ローカル文字列を作成します。ストリングがスコープ外に出る前に、ストリングのコピーを作成して返す必要があります。そのコピーはメインの文字列を構成するために使用されます。しかし、関数から文字列を移動した場合は、コピーを作成する必要はありません。

移動セマンティクスを理解しようとすると、誰かが私がやっていることがなぜ理にかなった理由を説明することができますか?関数からオブジェクトを移動することは可能ですか?


EDIT:

std::string && Get_String(void); 

std::string Get_String(void); 

に、まだ文字列を移動する方が効率的です:それはコンパイルし、私から関数のシグネチャを変更した場合、正しく動作します

この場合の返品期間中ですか?この例で考えると

+1

RVOは、その問題を解決します。 'std :: move'を使って無効にしないでください。 – chris

+0

@chris私は値を返すべきです。そして、コンパイラは私がやっていることに最適化しますか? –

+0

はい、現代のコンパイラはコピーを削除する必要があります。 – chris

答えて

16

は、

X foo() 
{ 
    X x;  
    return x; 
} 

次の動作が保証されています

Xがアクセス可能コピーを持っているか、コンストラクタを移動すると、コンパイラは コピーをElideのために選択することができます。これは、C++ 11以前でも指定されていた 最適化((N)RVO)という戻り値であり、ほとんどのコンパイラでは がサポートされています。
Xに移動コンストラクタがある場合は、xが移動されます。
Xにコピーコンストラクタがある場合は、xがコピーされます。
•それ以外の場合は、コンパイル時エラーが発生します。

X&& foo() 
{ 
    X x; 
    return x; // ERROR: returns reference to nonexistent object 
} 

右辺値参照は、参照され、ローカルオブジェクト手段を参照しながら、それを返す。返されたオブジェクトがローカル非静的オブジェクトである場合右辺値参照を返すことは誤りであることを

も注意 は、もう存在しないオブジェクトへの参照を返します。 std::move()を使用するかどうかは ではありません。

std::move()実際にはオブジェクトは移動しません。左辺値は左辺値に変換されます。

2

そのGet_String関数は、rvalue参照を関数ローカルオブジェクトにバインドします。Rvalue参照は破壊しようとしているものには便利ですが、すでに破棄されているものについては左辺値と同じくらい悪いものです。

機能のうち、ローカルオブジェクトを移動するには、あなただけのクラス型で返す:コンパイラは完全に移動/コピーを排除するために管理していない場合は

std::string Get_String(void) { 
    std::string str{"hello world"}; 
    return str; 
} 

、戻り値の呼び出し元こと

  • のように(自動記憶域期間を持つ何かを命名一時的、または
  • 単一の識別子:取得は限りreturn式があるとして、移動コンストラクタではなく、コピーコンストラクタを使用して構築されます上記)、または

  • std::move(something)
  • は(あなたはまだ明示する return std::move(str);を持つことができますが、それはここでは必要ありません。)