10

私は主にCとJavaのバックグラウンドからC++を学んでおり、オブジェクトをコピーせずにC++でオブジェクトを返すための最良の方法に興味があります。私の理解では、C ++ 11は、一時変数からデータを移動するために右辺値参照(&&)を導入しました(コピーとは対照的です)。例:

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();

どうもありがとうございました!

4

5 に答える 5

11

この質問はおそらく重複して閉じられます。よくある質問です。とにかくお答えしたいと思います。

C ++ 11では、のようなオブジェクトのクライアントである場合は、std::string値で渡す必要があり、効率についてはそれほど心配する必要はありません。

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

std::string hello = getStr();

このレベルでは、右辺値の参照を気にする必要はありません。std::string右辺値(からの戻り値などgetStr())から非常に効率的に「コピー」できることを知っておいてください。この「コピー」は実際には「移動」と呼ばれ、右辺値(匿名の一時)からコピーしているため、自動的に有効になります。

参照カウントに戻してコピーを最適化しようとしないでください。共有所有権のセマンティクスが必要な場合にのみ、参照カウントを使用してください。このステートメントは常に正しいとは限りません。しかし、基本を学ぶためには、従うのが経験則であるほど十分に近いです。

値で渡す必要のあるクラスを設計するときは、右辺値参照について心配し始める必要があります。

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

右辺値参照と移動セマンティクスの簡単な紹介として、N2027はまともなチュートリアルです。N2027は長すぎてここに貼り付けることができませんが、読みやすいように短すぎます。 std::stringN2027に定められた基本に従って、罪悪感のない価値でそれを渡すことができます。そして、あなたはあなたのでそれらの同じデザインパターンに従うことができますWidget

于 2012-07-08T00:50:29.023 に答える
2

多くの場合、メンバー変数へのconst参照を返すことで、コピーを回避できます。例えば:

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

これは実行時と同等return &centerであり、実際には、呼び出し元からメンバーに直接(読み取り専用)アクセスするだけでインライン化される可能性があります。

コンパイラを返すための一時的なものを作成する場合、最適化として余分なコピーを削除することができ、特別な構文は必要ありません。

于 2012-07-08T00:47:25.900 に答える
2

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


C ++は、オブジェクトを「値ごとに」渡すことを使用および推奨します。移動セマンティクスは、導入前よりも少ないコピーを作成しながら、コードがこれを実行できるようにする機能です。通常、コードは、移動セマンティクスの利点を得るために、右辺値参照型を直接使用する必要はありません。これは、一時オブジェクトが右辺値であり、過負荷解決によって右辺値参照を取得するメソッドが自動的に選択されるためです。

例えば:

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

std::string hello = getStr();

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

あなたもできると思いますが、すでにムーブが構築されているstd::string &&hello = getStr();ので、おそらく必要ありません。hello

私が考えることができる別の方法は、共有ポインタを使用することです

スマートポインタが提供する特定の所有権セマンティクスが本当に必要でない限り、スマートポインタは一般的に良い考えではないと思います。単純な「値による」受け渡しを使用するのが適切なデフォルトであり、移動セマンティクスでは通常、余分なコピーなしでそれを使用できます。

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

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

于 2012-07-08T02:18:26.637 に答える
1

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

于 2012-07-08T00:42:00.420 に答える
0

この場合にスマートポインタを使用したい場合は、unique_ptrの方が適しているかもしれません。

于 2012-07-08T00:48:23.340 に答える