简体   繁体   English

C ++ throw()优化

[英]C++ throw() optimization

According to Optimizing C++ , 根据优化C ++

Use the empty exception specification (that is, append throw() to the declaration) for the functions you are sure will never throw exceptions. 将空的异常规范(即,将throw()追加到声明中)用于您确定不会抛出异常的函数。

What if I know that 90% of my methods won't throw an exception? 如果我知道我的方法的90%不会抛出异常怎么办? It seems unconventional and verbose to append throw() to all of those methods. 将throw()附加到所有这些方法似乎是非常规且冗长的。 If not, what are the advantages? 如果没有,优势是什么? Or am I misunderstanding something here? 还是我误会了这里的东西?

C++11 has introduced noexcept , throw is somewhat deprecated (and according to this less efficient) C ++ 11引入了noexceptthrow稍微弃用(和根据这个效率较低)

noexcept is an improved version of throw(), which is deprecated in C++11. noexcept是throw()的改进版本,在C ++ 11中已弃用。 Unlike throw(), noexcept will not call std::unexpected and may or may not unwind the stack, which potentially allows the compiler to implement noexcept without the runtime overhead of throw(). 与throw()不同,noexcept不会调用std :: unexpected,并且可能会展开堆栈,也可能不会展开堆栈,这有可能允许编译器在没有throw()的运行时开销的情况下实现noexcept。

When an empty throw specification is violated, your program is terminated; 当违反空抛出规范时,程序将终止;否则,程序将终止。 this means you should only declare your functions as non throwing, only when they have a no throw exception guarantee. 这意味着仅当它们具有不引发异常保证时,才应将函数声明为不引发。

Finally you need a move constructor to be non throwing (specified with noexcept ) to be able to use the r-value ref version of std::vector<T>::push_back (see a better explanation here ) 最后,您需要一个不抛出noexcept的move构造函数(用noexcept指定),以便能够使用std::vector<T>::push_back的r值引用版本(请参见此处的详细说明)

The standard throw() doesn't enhance optimizability. 标准throw()不会增强可优化性。

If a method is marked as throw() then the compiler is forced to check if an exception is thrown from the method and unwind the stack - just like if the function is not marked as throw() . 如果将一个方法标记为throw()则编译器将被迫检查是否从该方法引发了异常并展开堆栈-就像该函数未标记为throw() The only real difference is that for a function marked throw() the global unexpected_handler will be called (which generally calls terminate() ) when the exception leaves the function, unwinding the stack to that level, instead of the behavior for functions without an exception specification which will handle the exception normally. 唯一真正的区别是,对于标记为throw()的函数,当异常离开函数时,将调用全局的unexpected_handler (通常调用terminate() ),将堆栈展开到该级别,而不是无异常的函数的行为规范将正常处理异常。

For pre-C++11 code, Sutter & Alexandrescu in "C++ Coding Standards" suggested: 对于C ++ 11之前的代码,“ C ++编码标准”中的Sutter和Alexandrescu建议:

Avoid exception specifications. 避免异常规范。

Take exception to these specifications: Don't write exception specifications on your functions unless you're forced to (because other code you can't change has already introduced them; see Exceptions). 请特别注意以下规范:不要在函数上编写异常规范,除非您被迫这样做(因为无法更改的其他代码已经引入了它们;请参阅“异常”)。

... ...

A common but nevertheless incorrect belief is that exception specifications statically guarantee that functions will throw only listed exceptions (possibly none), and enable compiler optimizations based on that knowledge 普遍但不正确的信念是,异常规范静态地保证函数将仅抛出列出的异常(可能不会抛出),并基于该知识启用编译器优化

In fact, exception specifications actually do something slightly but fundamentally different: They cause the compiler to inject additional run-time overhead in the form of implicit try/catch blocks around the function body to enforce via run-time checking that the function does in fact emit only listed exceptions (possibly none), unless the compiler can statically prove that the exception specification can never be violated in which case it is free to optimize the checking away. 实际上,异常规范实际上所做的只是一些微小的变化,但又有根本的不同:​​它们使编译器以隐式try / catch块的形式注入附加的运行时开销,以在函数体周围通过运行时检查来强制执行该函数是否确实在执行除非编译器可以静态证明永远不会违反异常规范,否则编译器仅发出列出的异常(可能不发出),在这种情况下可以自由地优化检查。 And exception specifications can both enable and prevent further compiler optimizations (besides the inherent overhead already described); 异常规范既可以启用也可以阻止进一步的编译器优化(除了已经描述的固有开销之外); for example, some compilers refuse to inline functions that have exception specifications. 例如,某些编译器拒绝内联具有异常规范的函数。

Note that in some versions of Microsoft's compilers (I'm not sure if this behavior has changed in more recent versions, but I don't think so), throw() is treated in a non-standard way. 请注意,在某些版本的Microsoft编译器中(我不确定这种行为在最近的版本中是否已更改,但我不认为如此), throw()以非标准的方式处理。 throw() is equivalent to __declspec(nothrow) which does allow the compiler to assume that the function will not have an exception thrown and undefined behavior will result if one is. throw()等效于__declspec(nothrow) ,它确实允许编译器假定函数不会抛出异常,如果抛出异常,则将导致未定义的行为。

C++11 deprecates the C++98 style exception specification and introduced the noexcept keyword. C ++ 11弃用了C ++ 98样式异常规范,并引入了noexcept关键字。 Bjarne Stroustup's C++11 FAQ says this about it: Bjarne Stroustup的C ++ 11常见问题对此进行了说明:

If a function declared noexcept throws (so that the exception tries to escape, the noexcept function) the program is terminated (by a call to terminate()). 如果声明为noexcept的函数抛出(从而使异常试图转义,则为noexcept函数),程序将终止(通过调用Terminate())。 The call of terminate() cannot rely on objects being in well-defined states (ie there is no guarantees that destructors have been invoked, no guaranteed stack unwinding, and no possibility for resuming the program as if no problem had been encountered). 终止()的调用不能依赖处于明确定义状态的对象(即,不能保证析构函数已被调用,不能保证堆栈展开,也不能像没有遇到问题一样恢复程序)。 This is deliberate and makes noexcept a simple, crude, and very efficient mechanism (much more efficient than the old dynamic throw() mechanism). 这是经过深思熟虑的,毫无例外地使它成为一种简单,原始且非常有效的机制(比旧的动态throw()机制要有效得多)。

In C++11 if an exception is thrown from a function marked as noexcept the compiler is not obligated to unwind the stack at all. 在C ++ 11中,如果从标记为noexcept的函数引发了异常,则编译器根本没有义务解开堆栈。 This affords some optimization possibilities. 这提供了一些优化的可能性。 Scott Meyers discusses the new noexcept in his forthcoming book "Effective Modern C++". 斯科特·迈耶斯(Scott Meyers)在即将出版的著作《有效的现代C ++》中讨论了新的noexcept

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM