C++ 当接口未被激活时,将派生实现标记为noexcept有什么副作用
我们有一个实现IUnknown(或任何我们不拥有的接口)的类。我们开始用noexcept标记大多数/所有方法,以进行任何潜在的优化,因为我们无论如何都不会抛出任何异常;虽然我们所依赖的一些图书馆是五月的。有人提出了这样一个问题:QueryInterface/AddRef/Release是否应该标记为noexcept,因为接口不是C++ 当接口未被激活时,将派生实现标记为noexcept有什么副作用,c++,inheritance,polymorphism,noexcept,C++,Inheritance,Polymorphism,Noexcept,我们有一个实现IUnknown(或任何我们不拥有的接口)的类。我们开始用noexcept标记大多数/所有方法,以进行任何潜在的优化,因为我们无论如何都不会抛出任何异常;虽然我们所依赖的一些图书馆是五月的。有人提出了这样一个问题:QueryInterface/AddRef/Release是否应该标记为noexcept,因为接口不是 当只有一些派生类被标记为noexcept时,是否有任何副作用或问题?通常,您应该小心使用noexcept。除非编译器能够证明函数确实不会抛出任何异常,否则它必须插入一个
当只有一些派生类被标记为noexcept时,是否有任何副作用或问题?通常,您应该小心使用
noexcept
。除非编译器能够证明函数确实不会抛出任何异常,否则它必须插入一个动态处理程序,以便在出现异常时终止程序。因此,它不一定会导致您希望的优化。在任何情况下,将其添加到AddRef
、Release
和QueryInterface
都应该是安全的
编辑
例如,考虑下面的代码:
extern int Foo();
int Bar() noexcept
{
return Foo();
}
这就是Clang 7.0在O3上产生的结果:
Bar(): # @Bar()
push rax
call Foo()
pop rcx
ret
mov rdi, rax
call __clang_call_terminate
__clang_call_terminate: # @__clang_call_terminate
push rax
call __cxa_begin_catch
call std::terminate()
如果删除noexcept
,则会得到以下结果:
Bar(): # @Bar()
jmp Foo() # TAILCALL
在本例中,主要的效果是图像有点膨胀,但请注意,对
Foo
的调用也变得效率较低。我始终建议尽可能添加noexcept
如果您将它添加到某个位置并因此而崩溃,那么您已经了解到您不能在该位置使用它以及原因。请注意,
noexcept
不是免费的。在所有功能上都使用它不是一个好主意。代价是一旦你戴上它,你就无法真正移除它。其他noexcept
代码可能依赖于函数的noexcept
,因此对于向后兼容性,您必须遵守。这意味着您永远无法将实现更改为可能抛出的内容。添加noexcept
是一条单行道,可以安全地添加(如果正确),但删除不安全。您必须确保函数本质上永远不会抛出。您所说的“插入动态处理程序”是什么意思?它是如何影响性能的?捕获异常并调用std::terminate
只需要一小段代码。这很少是一个问题。RCA的升级:工程师们知道他们不能在这个业务关键型功能上使用noexcept。