移動したオブジェクトで何ができますか?


138

規格は、オブジェクトが移動された後でオブジェクトに対して何ができるかを正確に定義していますか?移動元オブジェクトでできることはそれを破壊することだけだと思っていましたが、それだけでは不十分です。

たとえばswap、標準ライブラリで定義されている関数テンプレートを使用します。

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

明らかに、移動元のオブジェクトに割り当てることが可能でなければなりません。そうしないと、2行目と3行目が失敗します。では、移動元オブジェクトで他に何ができるでしょうか?これらの詳細を規格のどこに正確に見つけることができますか?

(ちなみに、なぜ1行目ではT c = std::move(a);なくなのT c(std::move(a));ですか?)

回答:


53

移動元オブジェクトは、指定されていないが有効な状態で存在します。これは、オブジェクトがもう多くのことを実行できない可能性がある一方で、そのすべてのメンバー関数は、定義された動作(operator=定義された状態のすべてのメンバーを含む)を示す必要があり、依然として破壊が必要であることを示唆しています。標準は各UDTに固有であるため、特定の定義はありませんが、標準タイプの仕様を見つけることができる場合があります。コンテナのようなものは比較的明白です—それらはコンテンツを移動するだけで、空のコンテナは明確に定義された有効な状態です。プリミティブは移動元のオブジェクトを変更しません。

補足:T c = std::move(a)moveコンストラクター(またはmoveが指定されていない場合はcopyコンストラクター)が明示的である場合、関数は失敗するためです。


26
そのメンバー関数のすべてが定義された動作を示すわけではありません。前提条件がないもののみ。たとえば、おそらくpop_back移動したくないでしょうvector。しかし、それが正しいかどうかは確かにわかりますempty()
ハワードヒンナン

6
@Howard Hinnant:pop_back空からvectorとにかく、メモリからは未定義の動作があるので、未定義の動作pop_backを示す移動されたベクトルからは一貫していると確信しています。
子犬

12
移動元のオブジェクトについて説明します。空の状態であることがわかっているオブジェクトではありません。移動元オブジェクトの状態は未指定です(もちろん、別段の指定がない限り)。[lib.types.movedfrom]
ハワード

5
@ハワード未指定ですが、有効なのでpop_back、有効なベクトルと同じように動作します(空のベクトルでもかまいません)。
クリスチャン・ラウ2011

1
この文脈での不特定で有効な意味は何ですか?
Ankur S

114

17.6.5.15 [lib.types.movedfrom]

C ++標準ライブラリで定義された型のオブジェクトは、(12.8)から移動される場合があります。移動操作は明示的に指定することも、暗黙的に生成することもできます。特に指定のない限り、そのような移動元のオブジェクトは、有効ですが指定されていない状態に置かれます。

オブジェクトが指定されていない状態にある場合、前提条件のないオブジェクトに対して任意の操作を実行できます。実行したい前提条件を持つ操作がある場合、オブジェクトの未指定状態が前提条件を満たしているかどうかわからないため、その操作を直接実行することはできません。

一般に前提条件を持たない操作の例:

  • 破壊
  • 割り当て
  • 以下のようなconstのオブザーバーgetemptysize

一般に前提条件がある操作の例:

  • 逆参照
  • pop_back

この回答はここでビデオ形式で表示されます:http : //www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s


1
しかし、他のオブジェクトと同じように、前提条件を簡単にチェックできますよね?
fredoverflow 2011

6
@FredOverflowもちろん、これらのチェック自体に前提条件がない限り。
クリスチャン・ラウ2011

1
@クリス:しかし、それは移動したオブジェクトではなく、通常のオブジェクトとどう違うのですか?
fredoverflow 2011

2
たぶん別の質問になるはずですが、それは意味があります:char* buffer;int length;メンバーの文字列がある場合、私の移動コンストラクター/割り当ては両方の値を交換(または設定)する必要がありますか?または、長さが指定されていなくても(それが意味をempty持ち、size無意味な値を返す場合)、問題はありませんか?
UncleBens 2011

3
@ 6502:意味がわからない。C ++ 03クラスは「C ++ 0x標準に違反しています」ではありません。これは、生成された移動アクタが標準に違反するためです。また、C ++ 03コードはそのクラスを移動しないので、移動トラクターが生成される理由はありません。
MSalters 2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.