C++核心准则编译边学-F.6 如果函数不会抛出异常,则声明为noexcept

共 3572字,需浏览 8分钟

 ·

2019-11-05 23:22

47533e46dcf8897198ff7e636dbf3c54.webp

F.6: If your function may not throw, declare it noexcept(如果函数不会抛出异常,则声明为noexcept)

Reason(原因)

If an exception is not supposed to be thrown, the program cannot be assumed to cope with the error and should be terminated as soon as possible. Declaring a function noexcept helps optimizers by reducing the number of alternative execution paths. It also speeds up the exit after failure.

如果经过推断不会抛出异常,程序就不必假设需要处理错误并且尽快终止执行。声明函数为noexcept可以通过减少可能的执行路径的方式帮助优化程序。这样做也会加速失败后的退出处理。

Example(示例)

Put noexcept on every function written completely in C or in any other language without exceptions. The C++ Standard Library does that implicitly for all functions in the C Standard Library.

为完全使用C写成或者不会发生异常的其他语言构成的函数增加noexcept修饰。C++标准库暗中为所有的C标准库函数做了相同的事情。


译者注:但是大师本人在《C++程序设计语言》的【13.1.7 异常与效率】一节中告诉我们要花点时间考虑一下。


Note(注意)

constexpr functions can throw when evaluated at run time, so you may need noexcept for some of those.

constexpr函数在运行时刻可以抛出异常,因此你可以为某些(不是全部)constexpr函数指定noexcept。


译者注:例如被0除。

Example(示例)

You can use noexcept even on functions that can throw:

你甚至可以对可以抛出异常的函数使用noexcept。

vector<string> collect(istream& is) noexcept{    vector<string> res;    for (string s; is >> s;)        res.push_back(s);    return res;}

If collect() runs out of memory, the program crashes. Unless the program is crafted to survive memory exhaustion, that may be just the right thing to do;terminate() may generate suitable error log information (but after memory runs out it is hard to do anything clever).

如果collect()在运行时耗尽了内存,程序就会崩溃。除非程序经过精心设计可以避免内存耗尽,这可能是可以做的唯一的事情了。terminate()可能生成适当的错误日志信息(但是当内存耗尽时,很难难精巧地完成任何事)


译者注:声明noexcept就是告诉编译器不需要生成捕获和向外传递异常的机制了。如果实际上发生了异常,其结果就如本节所描述。作者这里想说的应该是:错误指定noexcept属性是有风险的。


Note(注意)

You must be aware of the execution environment that your code is running when deciding whether to tag a function noexcept, especially because of the issue of throwing and allocation.  Code that is intended to be perfectly general (like the standard library and other utility code of that sort) needs to support environments where a bad_alloc exception may be handled meaningfully. However, most programs and execution environments cannot meaningfully handle a failure to allocate, and aborting the program is the cleanest and simplest response to an allocation failure in those cases.  If you know that your application code cannot respond to an allocation failure, it may be appropriate to add noexcept even on functions that allocate.

当需要决定是否为函数标记noexcept时,必须注意代码执行时所处的执行环境。最重要的原因是关于抛出异常和内存分配的议题。试图被完美地普遍使用的代码(例如标准库或其他类似代码)需要支持bad_loc异常可能被有意义地处理的环境(而不只是简单中止执行,译者注)。然而,大多数程序和执行环境无法有意义地处理分配内存失败,而且在那些情况下,中止程序是申请内存失败最干净和最简单的处理。如果你知道你的应用程序不能处理内存分配错误,哪怕函数包含内存分配动作,为其增加noexcept可能也是适当的。(这样可以触发terminate处理,译者注)

Put another way: In most programs, most functions can throw (e.g., because they use new, call functions that do, or use library functions that reports failure by throwing), so don't just sprinkle noexcept all over the place without considering whether the possible exceptions can be handled.

换句话说,大多数程序,大多数函数都会抛出异常(例如,它们可能是使用new,可能会调用可能抛出异常的函数,或者使用了通过抛出异常报告错误的库函数),因此不要在不考虑异常是否会被处理的情况下就到处使用noexcept。

noexcept is most useful (and most clearly correct) for frequently used, low-level functions.

noexcept对于那些经常使用的,低层次的函数特别有用(而且很容易判断正确性)。

Note(注意)

Destructors, swap functions, move operations, and default constructors should never throw. See also C.44.

析构函数,交换函数,移动操作和默认构造函数永远不应该抛出异常。参见C.44。

Enforcement(实施建议)
  • Flag functions that are not noexcept, yet cannot throw.

    标记那些没有noexcpet属性但是又不抛出异常的函数。

  • Flag throwing swap, move, destructors, and default constructors.

    标记抛出异常的交换/移动操作,析构函数和默认构造函数。


浏览 50
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报