C++ 当接口未被激活时,将派生实现标记为noexcept有什么副作用

C++ 当接口未被激活时,将派生实现标记为noexcept有什么副作用,c++,inheritance,polymorphism,noexcept,C++,Inheritance,Polymorphism,Noexcept,我们有一个实现IUnknown(或任何我们不拥有的接口)的类。我们开始用noexcept标记大多数/所有方法,以进行任何潜在的优化,因为我们无论如何都不会抛出任何异常;虽然我们所依赖的一些图书馆是五月的。有人提出了这样一个问题:QueryInterface/AddRef/Release是否应该标记为noexcept,因为接口不是 当只有一些派生类被标记为noexcept时,是否有任何副作用或问题?通常,您应该小心使用noexcept。除非编译器能够证明函数确实不会抛出任何异常,否则它必须插入一个

我们有一个实现IUnknown(或任何我们不拥有的接口)的类。我们开始用noexcept标记大多数/所有方法,以进行任何潜在的优化,因为我们无论如何都不会抛出任何异常;虽然我们所依赖的一些图书馆是五月的。有人提出了这样一个问题:QueryInterface/AddRef/Release是否应该标记为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。