14

私は単純なクラスを持っています:

class X
{
    std::string S;
    X (const std::string& s) : S(s) { }
};

最近右辺値について少し読んだことがありますが、右辺値を使用するためのコンストラクターを作成する必要があるかどうか疑問に思っていたので、タイプXの一時オブジェクトを検出できるでしょうか?std::string

私はそれが次のように見えるべきだと思います:

X (std::string&& s) : S(s) { }

私の知る限り、C++11 をサポートするコンパイラでの std::string の実装では、利用可能な場合はそのムーブ コンストラクタを使用する必要があります。

4

4 に答える 4

25
X (std::string&& s) : S(s) { }

これは rvalue を取るコンストラクターではなくrvalue-referenceを取るコンストラクターです。この場合、右辺値参照を使用しないでください。むしろ、値を渡してからメンバーに移動します。

X (std::string s) : S(std::move(s)) { }

経験則として、コピーする必要がある場合は、インターフェイスで行います。

于 2012-05-31T15:10:41.140 に答える
22

明確にするために:値渡しの答えは間違っていません。string&&しかし、1 つの詳細を除いて、どちらもオーバーロードを追加する最初の推測ではありません。

追加:

X (std::string&& s) : S(std::move(s)) { }

つまり、への右辺値参照の宣言された型がありますが、初期化に使用されるは型の左辺値式であるmoveため、がまだ必要です。sstring sSstring

実際、最初に提案したソリューション (移動を追加したもの) は、値渡しのソリューションよりもわずかに高速です。でもどちらも正しい。値渡しソリューションは、lvalue および xvalue 引数を X のコンストラクターに渡すときに、string の move コンストラクターを余分に呼び出します。

左辺値引数の場合、とにかくコピーが作成され、文字列のコピー コンストラクターは、文字列の移動コンストラクターよりもはるかにコストがかかる可能性があります (短い文字列バッファー内に収まる文字列を除きます。この場合、移動とコピーはほぼ同じです)。速度)。

xvalue 引数 (xvalue は に渡された左辺値std::move) の場合、値渡しソリューションでは、1 つではなく 2 つの移動構成が必要です。したがって、右辺値参照によるパス ソリューションの 2 倍のコストがかかります。しかし、それでも非常に高速です。

この投稿のポイントは、明確にすることです。値渡しは許容できるソリューションです。しかし、それが唯一の受け入れられる解決策ではありません。pass-by-rvalue-ref を使用したオーバーロードは高速ですが、必要なオーバーロードの数が、引数 N の数が増えるにつれて 2^N にスケーリングされるという欠点があります。

于 2012-05-31T15:59:31.533 に答える
14

いいえ、すべきではありません。あなたがすべきことは、現在のコンストラクターを次のようなものに置き換えることです:

X (std::string s) :S(std::move(s)) {}

これで、パラメーターにコピーされてからクラスの文字列に移動される左辺値と、2 回移動される右辺値の両方を処理できるようになりました (コンパイラは、この余分な作業を最適化できることを願っています)。

ほとんどの場合 (ここでは説明しない例外があります)、作成するクラスのムーブ コンストラクターを除いて、右辺値参照を取る関数を作成するべきではありません。値の独自のコピーが必要なときはいつでも、これはコンストラクターだけに適用されるわけではありません。値によって取得し、必要な場所に移動する必要があります。右辺値または左辺値のどちらを受け取るかに基づいて、値をコピーするか移動するかをクラス独自の移動コンストラクターに決定させます。結局のところ、r 値参照は、私たちの生活を難しくするのではなく、簡単にするために導入されました。

于 2012-05-31T15:09:36.217 に答える
5

引数のコピーが必要なので、パラメータを値で取得します。次に、それをメンバー データに移動します。与えられた引数が右辺値か左辺値かを検出するのはstd::stringコンストラクターであり、あなたではありません。

class X
{
    std::string s_;
    X(std::string s) : s_(std::move(s)) {}
};
于 2012-05-31T15:10:00.973 に答える