C++ 11中不推荐使用的throw-list

Per*_*-lk 44 c++ throw c++11

正如我在cppreference中看到的那样 ,经典的"throw"声明列表现在已在C++ 11中弃用.离开这个机制的原因是什么?我应该如何指定抛出我的函数的异常?

Pet*_*ter 48

有关更详细的推理,请参阅:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3051.html

如上文国家机构评论所述,例外规范在实践中并未证明有用.关于C++中的异常规范的问题有很多讨论(参见,例如,[Sutter02],[Boost03]),但主要问题是:

  • 运行时检查:在运行时而不是在编译时检查C++异常规范,因此它们不提供程序员保证已处理所有异常.运行时故障模式(调用std :: unexpected())不适合恢复.
  • 运行时开销:运行时检查要求编译器生成额外的代码,这些代码也会妨碍优化.
  • 通用代码中不可用:在通用代码中,通常不可能知道可能会对模板参数的操作抛出哪些类型的异常,因此无法编写精确的异常规范.

实际上,只有两种形式的异常抛出保证是有用的:操作可能抛出异常(任何异常)或操作永远不会抛出任何异常.前者通过完全省略异常规范来表达,而后者可以表示为throw()但很少是由于性能考虑.

[N3050]引入了一种新的异常规范,noexcept,指定该函数不会抛出任何异常.与throw()不同,noexcept不要求编译器引入代码来检查是否抛出异常.相反,如果通过异常退出指定为noexcept的函数,则结果是对std :: terminate()的调用.

随着noexcept的引入,程序员现在可以表达在实践中有用的两种异常保证,而无需额外的开销.因此,本文建议弃用"动态"异常规范,即那些写为throw(type-id-listopt)的规范.

  • 一个可悲的旁注是"noexcept"在实践中没用,因为它终止一个程序有什么样的帮助,而不是试图处理未能声明一个被认为是不可能但仍然发生的错误."如果我们(或其他人)失败,只需终止"似乎是错误处理的可怕策略. (2认同)
  • @ChristopherOezbek 这是一个完全有效的策略,因为如果您的应用程序处于您从未想过的状态,因此您通常不希望它继续做一些事情,因此也没有编码。应用程序最好立即退出,这样您就会立即发现有问题。 (2认同)
  • @ChristopherOezbek 你肯定希望你的数据库服务器崩溃(快速失败)而不是破坏你的数据库,就像一个例子。 (2认同)

Chr*_*bek 7

Peter给出的答案没有达到实现者和用户的异常规范的实际问题:

  • 如果实现者未能保证仅抛出定义的异常,则异常规范会导致程序终止(或者更准确地说是调用终止处理程序).
  • 因此,通过调用具有异常规范的方法,您作为库用户正在使您自己的代码容易完全失败/终止.如果库函数运行内存不足(std :: bad_alloc),您将无法捕获,但您将被终止.
  • 因此,最初的目标是传达最可能的失败选项并要求您作为用户来处理它们.
  • 作为另一方面的实现者,你不能真正调用任何其他没有异常规范的方法,因为这些方法可能会导致你终止你的调用者.一个可怕的地方.

结论是C++应该像Java那样:

  • 如果您调用具有异常规范的方法并且您自己有异常规范,那么您必须捕获异常或在您自己的异常规范中指定它.
  • 编译器强制执行此操作,而不执行其他运行时效果

Noexcept(因为C++ 11)遭受了相同的概念错误,因为如果规范也没有被遵守,它也会导致运行时终止,即一个方法抛出被声明不会.这使得noexcept不可能用于任何严重但最容纳的案例(移动构造函数浮现在脑海中).

  • 实际上,这是Java明显优于C++的极少数方面之一. (3认同)

dup*_*per 5

它们产生更慢和更大的代码,因为 libc++ 必须检查从函数传播出的任何异常是否违反了它的异常规范并调用std::unexpected. 这几乎没有用处,而且比仅仅记录函数自己抛出的异常更糟糕。