2012-07-08 14 views
9

私は主にCとJavaのバックグラウンドからC++を学習しています。オブジェクトをコピーせずにC++でオブジェクトを返す最良の方法は何かが不思議です。私の理解から、C++ 11は、(コピーに反対する)一時変数からデータを移動するために、rvalue参照(& &)を導入しました。例:C++でオブジェクトを返す

std::string getStr(){ 
    return "Hello"; 
} 

std::string &&hello = getStr(); 

別の方法として、共有ポインタを使用することが考えられます。

std::tr1::shared_ptr<std::string> getStr(){ 

    std::tr1::shared_ptr<std::string> hello(new std::string("Hello")); 
    return hello; 

} 

auto hello = getStr(); 

私は多分基準値の参照が良いと思っていますが、私はそれを使用する前に第二の意見を最初にしたいと思います。どちらが良いですか?

また、コンストラクタを使用して設定されない場合、クラス内のフィールドは右辺値参照にすることをお勧めしますか?例:

class StringHolder{ 

    public: 
    std::string &&str; 
}; 

StringHolder sh; 
sh.str = getStr(); 

皆さんありがとう!

+1

有用な参考書の紹介(http://www.artima.com/cppsource/rvalue.html) –

+0

現代の標準ライブラリの実装では、小さな文字列の最適化が使用されるため、文字列 "Hello"は値で返すよりも遅くなる可能性があります。 – bames53

答えて

10

この質問は重複している可能性があります。それはよく聞かれる質問です。しかし、私はとにかくそれに答えるつもりです。あなたはstd::stringのようなオブジェクトのクライアントである場合にC++ 11では、

は、あなたが値でそれを周りに渡すと効率についてはあまり心配しないでください。あなたが必要としない。このレベルでは

std::string getStr(){ 
    return "Hello"; 
} 

std::string hello = getStr(); 

r値の参照に関係する。ちょうどstd::stringが効率(getStr()からの返品)非常にからの値を "コピー"できることを知っています。この「コピー」は実際には「移動」と呼ばれ、rvalue(匿名の一時的なもの)からコピーしているため自動的に有効になります。

参照カウントに戻ってコピーを最適化しようとしないでください。 共有所有権の意味が必要な場合にのみ参照カウントを使用してください。この文はではなく、常にとなります。しかし、基本を学ぶためには、それは親指の良いルールです十分に近いです。N2027がまともなチュートリアルで、参照を右辺値とセマンティクスを移動するための簡単な概要については

class Widget 
{ 
    // pointer to heap data 
public: 
    // ... 
}; 

はあなたが値によって周りに渡す必要がある、あなたのクラスを設計するときは右辺値参照の心配を開始する必要があります。 N2027は長すぎてここに貼り付けることはできませんが、読みやすいように短くしてください。 std::stringはN2027に書かれている基本的なことを踏襲しており、価値のある罪悪感を無償で渡すことができます。そして、あなたはWidgetの同じデザインパターンに従うことができます。

+0

ありがとうございました!私はチュートリアルと移動コンストラクタの概念をゆっくり理解しています。stdのほとんどのオブジェクトは、ベクトルなどの移動コンストラクタを持っていますか(つまり、大きなベクトルを値で返すのはスマートですか)? また、あなたの例のWidgetクラスでは、この例に固有の「ポインタへのポインタ」のコメントか、値型とは対照的にポインタをフィールドとして使用する方が一般的です(ポインタの使用を推測します値のフィールドは状況に依存する)? – DanB91

+0

また、これはオブジェクトの移動コンストラクタに依存していることがわかりますが、obj o = std :: move(p);がある場合は一般的なルールとして仮定しています。 – DanB91

+0

@ DanB91:それが割り当てられていない限り、とにかく。 – ildjarn

1

参考値の参照ではなく、固有の言語機能であるため、値の参照ははるかに高速になります。ここでスマートまたは共有ポインタを使用すると、利得が得られず、明瞭性が大幅に低下します。しかし、右辺値の参照は、言語の一部であるのように設計されています。 rvalue参照を使用します。

2

しばしば、メンバ変数へのconst参照を返すことによってコピーを避けることができます。例えば:

class Circle { 
    Point center; 
    float radius; 
public: 
    const Point & getCenter() const { return center; }; 
}; 

これは、実行中のreturn &centerに相当し、実際にそう単に発呼者からメンバーの直接(読み取り専用)アクセスをもたらすインライン化されます。

コンパイラを返すために一時的な構造を構築する場合、特殊な構文を必要とせずに余分なコピーを最適化として削除することがあります。

0

この場合スマートポインタを使用する場合は、多分unique_ptrを使用する方がよいでしょう。

2

デフォルトでは、値渡しするだけです。関数がパラメータを変更またはコピーする必要がない場合は、const&によって取り込むことができますが、それ以外の場合は値でパラメータを取るだけです。オブジェクトを値で返し、セマンティクスまたはRVOを移動してコピーを避ける。


C++は '値ごとに'オブジェクトを渡して使用することを奨励します。移動セマンティクスは、コードが導入される前より少ないコピーを作成しながらこれを行うことを可能にする機能です。通常、コードは、移動セマンティクスの利点を得るために、rvalue参照型を直接使用する必要はありません。これは、一時オブジェクトがrvaluesであり、オーバーロードの解像度が自動的にrvalue参照を取得するメソッドを選択するためです。例えば

std::string getStr(){ 
    return "Hello"; 
} 

std::string hello = getStr(); 

このコードは、セマンティクスを移動使用します。 return "Hello"は文字列を一時的に構築するので、戻り値オブジェクトを初期化するために使用されるコンストラクタは移動コンストラクタになります(実際には戻り値の最適化によってこの動きはほぼ確実に回避されます)。 getStr()によって返される値は一時的なものなので、string helloのために選択されたコンストラクタは再び移動コンストラクタです。

std::string &&hello = getStr();でもできると思いますが、おそらくhelloは既に移動されているため、おそらく必要ありません。私は考えることができ

もう一つの方法は、私はあなたが本当に彼らが提供する特定の所有権のセマンティクスを必要としない限り、スマートポインタは、一般的に良いアイデアだと思いません共有ポインタ

を使用しています。単純な「値渡し」の使用は適切なデフォルトであり、移動セマンティクスは通常、余分なコピーをせずに使用できます。

また、クラス内のフィールドは、コンストラクタを使用して設定されない場合、rvalue参照にすることをお勧めしますか?

いいえ、メンバーの参照は、通常はお勧めできません。彼らは物事をより複雑にし、あなたの例が示すようにそれらを使用することさえ許されません。あなたのサンプルコードが許可されている場合、存在しないオブジェクトに割り当てようとしているので、sh.str = getStr();は未定義の動作になります。それはstd::string *str; *str = getStr();のようです。

+0

私が集めたことから、値の参照は破棄されないように戻り値を保存すると考えました。実際、私は簡単な "std :: string && hello = getStr();"を書きました。 hello = * hello = getStr();を実行するのとは対照的に、明らかにseg faultを引き起こしました)。しかし、今私はゆっくりと&&の使い方を理解しており、オブジェクトを値で返すようアドバイスを取っています(小さなものであれ、移動コンストラクターを実装しているものであれ)。ありがとう! – DanB91

+0

@ DanB91実際には、右辺値参照で戻り値を取り込むことが正しいと思います。 – bames53

関連する問題