我相信我们正在研究标准缺陷。如果将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
这项调查大约有一年的历史,但据我所知仍然有效。