標準の欠陥を見ていると思います。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 年前のものですが、私の知る限り、まだ有効です。