std::function的移动赋值不是noexcept,但std::function::swap是。这是怎么回事?

6

std::function的概述在func.wrap.func中告诉我们:

function& operator=(function&&);

移动赋值运算符不是noexcept,不能与move only类型在标准容器中一同使用。

但是! 它还告诉我们:

void swap(function&) noexcept;

同样地,默认构造函数为:

function() noexcept;

因此,我们可以实现移动构造函数,先使用默认构造函数,然后再进行swap。

由于我们可以使用swap实现移动赋值运算符(swap具有更强的后置条件):

  • 如何在std::function中实现一个noexcept交换?
  • 为什么std::function的移动赋值运算符不是noexcept
1个回答

5

如何在std::function中实现noexcept交换?

std::function对象不一定直接包含目标。它可能包含指向动态分配的内存副本的指针。它可能因为几乎任何原因而这样做。最常见的原因是目标太大,无法直接适应function,但对于任何其他防止function满足其要求的情况也是如此。如果function仅保存指针,则该指针可以轻松地移动到另一个function

std::function的移动赋值运算符为什么不是noexcept

没有很好的理由,因此在未来的C++版本中有一个提案将其改为noexceptp0771r0。它指出,与标准规定相反,一些实现已经将其标记为noexcept


基本上,为了利用小对象优化,我们会检测对象是否小且移动操作是noexcept的。否则,我们将其视为“大对象”并将其放在指针后面,这个指针是可以轻松进行noexcept移动和交换的。这回答了我的问题。 - milleniumbug
通过小缓冲区优化和包含可调用的移动和复制操作,我们如何实现无抛出的交换? - Yakk - Adam Nevraumont
@Yakk 我们不会。我们确保从一开始就不会陷入这种情况。 - user743382
1
@Yakk 一个带有抛出移动的函数对象将被取消小缓冲优化。(请参见我上面的评论) - milleniumbug

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接