我认为这是一个标准缺陷。如果要将 noexcept
规范应用于移动赋值运算符,那么会有一些复杂性。我相信,不管我们谈论的是 basic_string
还是 vector
,这个说法都是正确的。
基于 [container.requirements.general]/p7 的规定,容器移动赋值运算符应该做到:
C& operator=(C&& c)
如果
alloc_traits::propagate_on_container_move_assignment::value
为
true
,则释放资源、移动分配器并从
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()
,则移动分配每个
c[i]
。当
alloc_traits::propagate_on_container_move_assignment::value::true
时,可以指定移动赋值运算符为
noexcept
,因为它只会释放当前资源,然后从源中窃取资源。此外,在这种情况下,分配器也必须被移动赋值,并且该移动赋值必须是
noexcept
的,以使容器的移动赋值成为
noexcept
。当
alloc_traits::propagate_on_container_move_assignment::value::false
并且两个分配器相等时,将执行与#2相同的操作。然而,只有在运行时才知道分配器是否相等,因此无法基于此可能性确定
noexcept
。当
alloc_traits::propagate_on_container_move_assignment::value::false
并且两个分配器不相等时,必须移动分配每个单独的元素。这可能涉及向目标添加容量或节点,因此本质上是
noexcept(false)
的。
C& operator=(C&& c)
noexcept(
alloc_traits::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value);
我在上面的规范中看不到对 C::value_type
的依赖,因此我认为它同样适用于 std::basic_string
,尽管 C++11 有所不同。
更新:
在下面的评论中,Columbo 正确指出一切都在逐渐变化。 我上面的评论是针对 C++11 的。
对于草案 C++17(目前似乎很稳定),情况有所改变:
- 如果
alloc_traits::propagate_on_container_move_assignment::value
为 true
,则规范现在要求移动分配器类型不会抛出异常(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{});
对于std::allocator<T>
,alloc_traits::propagate_on_container_move_assignment{}
和alloc_traits::is_always_equal{}
都为真。
此外,现在在C++17草案中,vector
和string
的移动赋值操作都恰好具有这个noexcept
规范。然而,其他容器则具有此noexcept
规范的变体。
如果您关心此问题,最安全的做法是测试您关心的容器的显式特化。我已经在这里针对VS、libstdc++和libc++做了这件事:
http://howardhinnant.github.io/container_summary.html
这项调查已经大约一年了,但据我所知仍然有效。
noexcept
。 - Nicol Bolas