在接口不是时标记派生实现 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
。除非编译器可以证明该函数确实不会抛出任何异常,否则它必须插入一个动态处理程序以在出现异常时终止您的程序。因此,它不一定会导致您希望的优化。无论如何,将其添加到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。
如果您将它添加到某个位置并因此崩溃,您刚刚了解到您不能在那里使用它以及原因。
我们有一个 class 实现了 IUnknown(或我们不拥有的任何接口)。我们开始将 most/all 方法标记为 noexcept 以进行任何潜在的优化,因为无论如何我们都不会抛出任何异常;尽管我们依赖的一些库可能。有人提出了 QueryInterface/AddRef/Release 是否应该标记为 noexcept 的问题,因为接口不是。
当只有一些派生的 classes 被标记为 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。
如果您将它添加到某个位置并因此崩溃,您刚刚了解到您不能在那里使用它以及原因。