4
votes

We have a class which implements IUnknown (or any interface which we don't own). We started marking most/all of our methods with noexcept for any potential optimization since we don't throw any exceptions anyway; although some of the libraries we depend on may. The question was raised whether or not QueryInterface/AddRef/Release should be marked noexcept since the interface isn't.

Are there any side effects or gotchas when only some of the derived classes are marked noexcept?

2
Beware that noexcept isn't free. It's not a great idea to throw it on all the functions. The cost is that you can't really remove it once you've put it on. Other noexcept code might rely on your function's noexcept so for backwards compatibility you are stuck with. That means you can't ever change the implementation to something that might throw. Adding noexcept is a one way street, safe to add (if it's correct) but unsafe to remove. You have to be sure that the function, intrinsically, could never throw. - François Andrieux

2 Answers

4
votes

You should be careful with noexcept in general. Unless the compiler can prove that the function really won't throw any exceptions, then it must insert a dynamic handler to terminate your program in case of an exception. Thus it won't necessarily lead to the optimizations you're hoping for. In any case, adding it to AddRef, Release, and QueryInterface should be safe.

Edit

For example, consider the following code:

extern int Foo();

int Bar() noexcept
{
    return Foo();
}

This is what Clang 7.0 generates on 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()

If you delete the noexcept, you get this instead:

Bar():                                # @Bar()
    jmp     Foo()                 # TAILCALL

In this example, the primary effect is just to bloat the image a little bit, but notice that the call to Foo also became a little less efficient.

0
votes

I would always recommend adding noexcept wherever you can.

If you add it to a location and crash because of it, you've just learned that you can't use it there along with the reason why.