我相信我们正在研究标准缺陷。如果将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
and get_allocator() == c.get_allocator()
,则转储资源,并从 传输资源c
。
如果
alloc_traits::propagate_on_container_move_assignment::value
是false
and get_allocator() != c.get_allocator()
,则移动分配每个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 相同的事情。但是,直到运行时才知道分配器是否相等,因此您不能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 另有规定。
更新
在下面的评论中,哥伦布正确地指出,事情一直在逐渐发生变化。我上面的评论是相对于 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{});
并且,对于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
这项调查大约有一年的历史,但据我所知仍然有效。