標準の欠陥を見ていると思います。noexceptムーブ代入演算子に適用する場合、仕様がやや複雑になります。そして、私たちが話しているのbasic_stringがvector.
[container.requirements.general]/p7 に基づいて、コンテナー移動割り当てオペレーターが行うべきことの私の英語の翻訳は次のとおりです。
C& operator=(C&& c)
alloc_traits::propagate_on_container_move_assignment::valueが
の場合true、 リソースをダンプし、 move がアロケータを割り当て、 からリソースを転送しcます。
alloc_traits::propagate_on_container_move_assignment::valueがfalse
との場合
、 はget_allocator() == c.get_allocator()リソースをダンプし、 からリソースを転送しcます。
alloc_traits::propagate_on_container_move_assignment::valueがfalse
との場合
get_allocator() != c.get_allocator()、move はそれぞれに を割り当てますc[i]。
ノート:
alloc_traitsを指しallocator_traits<allocator_type>ます。
現在のリソースの割り当てを解除し、ソースからリソースを盗むだけであるためalloc_traits::propagate_on_container_move_assignment::value、true移動割り当て演算子を指定できるのはいつですか。noexceptまた、この場合、アロケーターにも移動が割り当てられている必要があり、その移動の割り当てはnoexcept、コンテナーの移動の割り当てがnoexcept.
がalloc_traits::propagate_on_container_move_assignment::valueでfalse、2 つのアロケータが等しい場合、#2 と同じことを行います。ただし、アロケーターが実行時まで等しいかどうかはわからないためnoexcept、この可能性に基づくことはできません。
がalloc_traits::propagate_on_container_move_assignment::valueでfalse、2 つのアロケータが等しくない場合、個々の要素を移動して割り当てる必要があります。これには、ターゲットへの容量またはノードの追加が含まれる場合があるため、本質的にnoexcept(false).
要約すると:
C& operator=(C&& c)
noexcept(
alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value);
また、上記の仕様には への依存が見られないため、 C++11 が別の方法で指定しているにもかかわらずC::value_type、 にも同様に適用されるはずです。std::basic_string
アップデート
以下のコメントで、コロンボは物事が常に徐々に変化していることを正しく指摘しています。上記の私のコメントは C++11 に関連しています。
ドラフト C++17 (現時点では安定しているように見えます) では、状況が若干変更されています。
が の場合、仕様でalloc_traits::propagate_on_container_move_assignment::valueは、例外をスローしないtrueように の移動割り当てが必要になりましたallocator_type(17.6.3.5 [allocator.requirements]/p4)。したがって、もうチェックする必要はありませんis_nothrow_move_assignable<allocator_type>::value。
alloc_traits::is_always_equal追加されました。これが真である場合、コンパイル時に、リソースを転送できるため、上記のポイント 3 をスローできないと判断できます。
したがって、noexceptコンテナーの新しい仕様は次のようになります。
C& operator=(C&& c)
noexcept(
alloc_traits::propagate_on_container_move_assignment{} ||
alloc_traits::is_always_equal{});
そして、 for std::allocator<T>、alloc_traits::propagate_on_container_move_assignment{}とalloc_traits::is_always_equal{}は両方とも真です。
また、現在 C++17 ドラフトでは、vectorとstring移動代入の両方に、まさにこのnoexcept仕様が適用されています。noexceptただし、他のコンテナにはこの仕様のバリエーションがあります。
この問題が気になる場合に最も安全な方法は、気になるコンテナーの明示的な特殊化をテストすることです。container<T>ここで、VS、libstdc ++、およびlibc ++に対して正確にそれを行いました:
http://howardhinnant.github.io/container_summary.html
この調査は約 1 年前のものですが、私の知る限り、まだ有効です。