c++ - 为什么 std::vector 允许对其包含的类型使用可抛出的移动构造函数?
问题描述
显然,std::move_if_noexcept()
将调用移动构造函数,即使它没有被标记为noexcept
好像没有可用的复制构造函数。
来自cpprefeerence.com(强调我的):
笔记
例如,这由 使用
std::vector::resize
,它可能必须分配新存储,然后将元素从旧存储移动或复制到新存储。如果在此操作期间发生异常,std::vector::resize
则撤消它到目前为止所做的一切,这只有std::move_if_noexcept
在用于决定是使用移动构造还是复制构造时才有可能。(除非复制构造函数不可用,在这种情况下,无论哪种方式都使用移动构造函数,并且可以放弃强异常保证)
与std::vector
在重新分配中使用此函数一样,这可能会使向量以及可能的应用程序处于未确定状态。那么,为什么会允许这样做呢?
解决方案
假设你正在做vector
它会使用时正在做的事情move_if_noexcept
。也就是说,你有一些 object obj
,你需要从 构造一个该类型的新值obj
。之后,您将删除obj
. 这是移动物体的主要情况vector
,在可能的情况下也是如此。
如果运动是noexcept
,那么obj
根据定义,运动是异常安全的。如果不是 noexcept
,那么您需要问:如果移动构造函数抛出,会发生什么?在那种情况下是什么状态obj
?答案是……你不知道。更糟糕的是,您已经成功移动的任何对象的状态如何?你能把它们搬回来吗?
但是,当涉及到复制构造函数时,您确实知道. 复制构造函数将 aconst&
传递给源对象。所以根据定义,一个失败的复制操作不能修改obj
(是的,我们知道你可以const_cast
,但这使你的复制构造函数成为一个谎言。这样的谎言是为什么auto_ptr
不再存在,我猜想在谎言复制构造函数的标准)。因此,在失败的副本上,obj
处于其原始状态。
因此,如果运动可以抛出,则首选复制,因为这提供了强大的异常保证:在发生异常时,一切都会恢复原状。
但是,如果您唯一的选择是投掷动作,那么您有两个选择:使这种类型永远不能与 一起使用vector
,或者提供任何异常保证该类型本身在移动失败时提供的任何异常保证。后者是被选择的。
这是允许的,因为那是你要求的。您选择的类型不允许强异常保证,因此无法提供。但是你仍然可以制作一个vector
这样的类型;您只需要处理不可复制的移动失败的可能性。
而且由于您是那种使用无法提供强大异常保证的类型的人,您显然必须知道如何处理这些情况,对吧?
推荐阅读
- javascript - 如果用户输入与预定义字符串匹配,则返回 true
- django - 菜单中的 Django CMS 图标
- android - 领域避免更新嵌套对象
- angular - 我需要帮助了解如何将此函数转换为流以获得响应和最新的结果
- kubernetes - Kubernetes 自动移除不再需要的资源
- testing - 在测试时模拟单个函数存在哪些模式?
- c# - Simple Injector 只注册具有多参数构造函数的类的一个参数
- c++ - 让 datadog 监听 C++ 中的套接字
- python - Get XPath to attribute
- arrays - 如何在 BigQuery 中声明列表/数组/结构类型变量