11

このプログラムをC++11コンパイラでコンパイルする場合、ベクトルは関数の外に移動されません。

#include <vector>
using namespace std;
vector<int> create(bool cond) {
    vector<int> a(1);
    vector<int> b(2);

    return cond ? a : b;
}
int main() {
    vector<int> v = create(true);
    return 0;
}

このようにインスタンスを返すと移動します。

if(cond) return a;
else return b;

これがideoneのデモです。

gcc4.7.0とMSVC10で試してみました。どちらも同じように動作します。
これが発生する理由は次
のとおりです。三項演算子の型は、returnステートメントが実行される前に評価されるため、左辺値です。この時点で、aとbはまだxvaluesではありません(まもなく期限切れになります)。
この説明は正しいですか?

これは規格の欠陥ですか?
これは明らかに意図された動作ではなく、私の意見では非常に一般的なケースです。

4

2 に答える 2

8

これで修正されます

return cond ? std::move(a) : std::move(b);

あなたのコードがそうであるように、三項演算子を関数として考えてください

return ternary(cond, a, b);

パラメータは暗黙的に移動されません。明示的にする必要があります。

于 2012-08-26T18:27:32.807 に答える
8

関連する標準見積もりは次のとおりです。

12.8段落32:

コピーの省略は、次の状況で許可されます[...]

  • クラス戻り型を持つ関数のreturnステートメントで、式が関数戻り型と同じcv-unqualified型を持つ不揮発性自動オブジェクト(関数またはcatch-clauseパラメーター以外)の名前である場合、自動オブジェクトを関数の戻り値に直接構築することにより、コピー/移動操作を省略できます。
  • 【ご利用時throw、条件付き】
  • [ソースが一時的なもので、条件付きの場合]
  • [catch値で、条件付きで]

パラグラフ33:

ソースオブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値で指定されていることを除いて、コピー操作の省略基準が満たされている、または満たされる場合、コピーのコンストラクターを選択するためのオーバーロード解決は次のようになります。最初は、オブジェクトが右辺値で指定されているかのように実行されます。オーバーロード解決が失敗した場合、または選択したコンストラクターの最初のパラメーターのタイプがオブジェクトのタイプへの右辺値参照ではない場合(おそらくcv修飾)、オブジェクトを左辺値と見なして、オーバーロード解決が再度実行されます。[注:この2段階の過負荷解決は、コピーの省略が発生するかどうかに関係なく実行する必要があります。省略が実行されない場合に呼び出されるコンストラクターを決定し、呼び出しが省略された場合でも、選択されたコンストラクターにアクセスできる必要があります。-エンドノート]

の式はreturn (cond ? a : b);単純な変数名ではないため、コピーの省略や右辺値の処理には適していません。少し残念かもしれませんが、コンパイラの実装に対する期待の頭痛の種が生じるまで、例を少しずつ拡張することは容易に想像できます。

std::moveもちろん、安全であることがわかっているときに戻り値に明示的に言うことで、これらすべてを回避できます。

于 2012-08-26T18:56:52.773 に答える