Seb*_*edl 66
标准的策略noexcept是仅标记不能或不能失败的函数,而不是那些仅指定不抛出异常的函数.换句话说,所有具有有限域的函数(传递错误的参数并且您得到未定义的行为)都不会noexcept,即使它们未被指定抛出也是如此.
被标记的函数是swap(必须不会失败,因为异常安全通常依赖于它)和numeric_limits::min(不能失败,返回基本类型的常量).
原因是实现者可能希望提供其库的特殊调试版本,这些版本会引发各种未定义的行为情况,以便测试框架可以轻松检测到错误.例如,如果您使用带有索引的索引vector::operator[],或者调用front或back使用空向量.有些实现想要在那里抛出一个异常(它们被允许:因为它是未定义的行为,它们可以做任何事情),但是noexcept对这些函数强制执行标准会使这变得不可能.
Xin*_*ang 16
作为@SebastianRedl回答的补充:你为什么需要noexcept?
你可能已经知道,a vector有它的容量.如果它已满push_back,它将分配更大的内存,将所有现有元素复制(或从C++ 11移动)到新的主干,然后将新元素添加到后面.

但是,如果在分配内存或将元素复制到新主干时抛出异常怎么办?
如果在分配内存期间抛出异常,则向量处于其原始状态.只需重新抛出异常并让用户处理它就可以了.
如果在复制现有元素期间抛出异常,则通过调用析构函数将销毁所有复制的元素,释放已分配的中继,并抛出异常以由用户代码处理.(1)
在摧毁一切之后,矢量恢复到原始状态.现在可以安全地抛出异常让用户处理它,而不会泄漏任何资源.
来到C++ 11时代,我们有一个强大的武器叫做move.它允许我们从未使用的对象中窃取资源.的std ::矢量将使用move时,它需要增加(或减少)的能力,只要该move操作是noexcept.
假设在移动期间抛出异常,前一个中继与之前move的中断不同:资源被盗,使向量处于中断状态.用户无法处理异常,因为所有内容都处于非确定状态.

这就是为什么std::vector依赖于move constructor被noexcept.
这是客户端代码如何依赖于noexcept接口规范的演示.如果以后noexcept不满足要求,以前依赖它的任何代码都将被破坏.
noexcept?简短回答:异常安全代码很难写.
答案noexcept很长:对实现接口的开发人员设置严格的限制.如果noexcept要从接口中删除,客户端代码可能会像上面给出的向量示例一样被破坏; 但是如果你想创建一个界面noexcept,你可以随时自由地进行.
因此,仅在必要时将接口标记为noexcept.
在2013年的Going Native中,Scott Meyers谈到了上述情况,即如果没有noexcept,程序的完整性就会失败.
我还写了一篇关于它的博客:https://xinhuang.github.io/posts/2013-12-31-when-to-use-noexcept-and-when-to-not.html
| 归档时间: |
|
| 查看次数: |
2660 次 |
| 最近记录: |