私はこのパーティーに遅れて参加し、現時点で他の回答が完全に正しいとは思わないため、追加の回答を提供します。
質問:
移動元のベクトルは常に空ですか?
答え:
通常、常にではありません。
悲惨な詳細:
vector一部のタイプのように、標準定義の移動元状態はありません (たとえば、移動元の後にunique_ptr等しいと指定されています)。nullptrただし、要件vectorはそれほど多くのオプションがないようなものです。
vector答えは、のムーブ コンストラクターとムーブ代入演算子のどちらについて話しているかによって異なります。vector後者の場合、答えはのアロケータにも依存します。
vector<T, A>::vector(vector&& v)
この操作の複雑さは一定でなければなりません。vつまり、constructからリソースを盗んで、空の状態の*thisままにする以外に選択肢がないことを意味します。vこれは、アロケーターAが何であれ、型Tが何であるかに関係なく当てはまります。
したがって、移動コンストラクターの場合、移動元vectorは常に空になります。これは直接指定されていませんが、複雑さの要件から外れており、それを実装する他の方法がないという事実です。
vector<T, A>&
vector<T, A>::operator=(vector&& v)
これはかなり複雑です。3 つの主要なケースがあります。
1:
allocator_traits<A>::propagate_on_container_move_assignment::value == true
(propagate_on_container_move_assignmentに評価されtrue_typeます)
この場合、move 代入演算子は 内のすべての要素を破壊*thisし、アロケータ from を使用して容量の割り当てを解除し、アロケータを*thismove 代入してから、メモリ バッファの所有権を から に転送vし*thisます。の要素の破棄を除いて*this、これは O(1) の複雑な操作です。また、通常 (すべてではありませんがほとんどの std:: アルゴリズムで)、move 割り当ての lhs は move 割り当てのempty() == true前にあります。
注: C++11 ではpropagate_on_container_move_assignmentforstd::allocatorは ですがfalse_type、これはtrue_typefor C++1y (y == 4 であることが望ましい) に変更されました。
One の場合、moved-fromvectorは常に空になります。
二:
allocator_traits<A>::propagate_on_container_move_assignment::value == false
&& get_allocator() == v.get_allocator()
(propagate_on_container_move_assignmentは に評価されfalse_type、2 つのアロケータは等しいと比較されます)
この場合、ムーブ代入演算子はケース 1 と同じように動作しますが、次の例外があります。
- アロケータは移動割り当てされていません。
- このケースとケース 3 の間の決定は実行時に行われ、ケース 3 はより多くの を必要
Tとするため、ケース 2 も必要になりますが、ケース 2 は でこれらの追加の要件を実際には実行しませんT。
ケース 2 では、moved-fromvectorは常に空になります。
三:
allocator_traits<A>::propagate_on_container_move_assignment::value == false
&& get_allocator() != v.get_allocator()
(propagate_on_container_move_assignmentは に評価されfalse_type、2 つのアロケータは等しくありません)
vこの場合、実装はアロケータを移動して割り当てることも、リソースを転送することもできません*this(メモリ バッファであるリソース)。この場合、移動代入演算子を効果的に実装する唯一の方法は次のとおりです。
typedef move_iterator<iterator> Ip;
assign(Ip(v.begin()), Ip(v.end()));
つまり、各個体Tを からvに移動し*thisます。は、利用可能な場合はとのassign両方を再利用できます。たとえば、実装と同じものを持っている場合は、それぞれを からに割り当てることができます。これは である必要があります。移動代入演算子が必要ないことに注意してください。コピー代入演算子でも十分です。 just は右辺値から割り当て可能でなければならないことを意味します。capacitysize*this*thissizevTv*thisTMoveAssignableMoveAssignableTMoveAssignableTT
sizeの*thisが十分でない場合は、で newTを構築する必要があります*this。これは である必要TがありますMoveInsertable。私が考えることができる正気のアロケーターはMoveInsertable、 と同じものにMoveConstructible要約されます。これは、右辺値から構築可能であることを意味しますT( の移動コンストラクターの存在を意味するものではありませんT)。
3 の場合、moved-fromvectorは一般に空にはなりません。移動元の要素でいっぱいになる可能性があります。要素に移動コンストラクターがない場合、これはコピー割り当てと同等になる可能性があります。ただし、これを強制するものは何もありません。実装者は、必要に応じて自由に追加の作業を行って実行し、空v.clear()のままにすることができます。v私は実装がそうしていることを認識していませんし、実装がそうする動機についても認識していません。しかし、私はそれを禁止するものは何も見ません。
v.clear()David Rodríguez は、この場合、 GCC 4.8.1 が呼び出し、v空 のままであると報告しています。libc++はそうではなく、v空ではありません。どちらの実装も準拠しています。