在接口不是时标记派生实现 noexcept 的副作用是什么

What are the side effects of marking a derived implementation noexcept while the interface is not

我们有一个 class 实现了 IUnknown(或我们不拥有的任何接口)。我们开始将 most/all 方法标记为 noexcept 以进行任何潜在的优化,因为无论如何我们都不会抛出任何异常;尽管我们依赖的一些库可能。有人提出了 QueryInterface/AddRef/Release 是否应该标记为 noexcept 的问题,因为接口不是。

当只有一些派生的 classes 被标记为 noexcept 时,是否有任何副作用或问题?

一般来说,您应该小心 noexcept。除非编译器可以证明该函数确实不会抛出任何异常,否则它必须插入一个动态处理程序以在出现异常时终止您的程序。因此,它不一定会导致您希望的优化。无论如何,将其添加到AddRefReleaseQueryInterface应该是安全的。

编辑

例如,考虑以下代码:

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。

如果您将它添加到某个位置并因此崩溃,您刚刚了解到您不能在那里使用它以及原因。