tl;dr : はい、 a を移動するstd::vector<T, A>
とイテレータが無効になる可能性があります
一般的なケース (std::allocator
インプレース) では、無効化は発生しませんが、保証はなく、実装が現在イテレーターを無効化していないという事実に依存している場合、コンパイラーを切り替えるか、次のコンパイラーの更新でさえ、コードの動作が正しくなくなる可能性があります。
移動中の割り当て:
move-assignment の後にイテレータが実際に有効なままであるかどうかという問題std::vector
は、アロケータのベクトル テンプレートの認識に関連しており、アロケータのタイプ (およびおそらくそのそれぞれのインスタンス) に依存します。
私が見たすべての実装で、std::vector<T, std::allocator<T>>
1の移動代入は、実際には反復子またはポインターを無効にしません。ただし、コンテナがアロケータを認識しているため、標準ではイテレータがインスタンスのすべての移動代入に対して有効であることを保証できないため、これを利用することになると問題があります。std::vector
カスタム アロケーターは状態を持っている場合があり、それらが移動代入時に伝搬されず、比較が等しくない場合、ベクターは独自のアロケーターを使用して、移動された要素にストレージを割り当てる必要があります。
させて:
std::vector<T, A> a{/*...*/};
std::vector<T, A> b;
b = std::move(a);
今なら
std::allocator_traits<A>::propagate_on_container_move_assignment::value == false &&
std::allocator_traits<A>::is_always_equal::value == false &&
(おそらく c++17 以降)
a.get_allocator() != b.get_allocator()
次に、b
新しいストレージを割り当て、要素をa
1 つずつそのストレージに移動するため、すべての反復子、ポインター、および参照が無効になります。
その理由は、上記の条件1.を満たすと、コンテナーの移動時にアロケーターの移動割り当てが禁止されるためです。したがって、アロケータの 2 つの異なるインスタンスを処理する必要があります。これらの 2 つのアロケーター オブジェクトが常に等しい ( 2. ) と比較されるわけでも、実際に等しいと比較されるわけでもない場合、両方のアロケーターの状態が異なります。アロケータは、異なる状態x
の別のアロケータのメモリの割り当てを解除できない場合があるため、アロケータを持つコンテナは、 を介してメモリを割り当てたコンテナからメモリを盗むことはできません。y
x
y
アロケータが移動代入で伝播する場合、または両方のアロケータが同等であると比較した場合、ストレージを適切に解放できることが確実であるため、実装はb
独自のデータを作成することを選択する可能性が非常に高くなります。a
1 :std::allocator_traits<std::allocator<T>>::propagate_on_container_move_assignment
化れていない) のstd::allocator_traits<std::allocator<T>>::is_always_equal
typdef です。std::true_type
std::allocator
移動中の建設:
std::vector<T, A> a{/*...*/};
std::vector<T, A> b(std::move(a));
アロケーター対応コンテナーの移動コンストラクターは、現在の式の移動元のコンテナーのアロケーター インスタンスからそのアロケーター インスタンスを移動構築します。したがって、適切な割り当て解除機能が保証され、メモリが盗まれる可能性があります (実際には盗まれる可能std::array
性があります)。
注: イテレータが移動の構築に対しても有効であるという保証はまだありません。
スワップ時:
スワップ後も 2 つのベクトルのイテレータが有効なままであるように要求するのは簡単です (現在は、それぞれのスワップされたコンテナーを指すだけです)。
std::allocator_traits<A>::propagate_on_container_swap::value == true ||
a.get_allocator() == b.get_allocator()
したがって、アロケーターがスワップ時に伝搬されず、それらが等しくない場合、コンテナーのスワップはそもそも未定義の動作です。