Search code examples
c++inheritancepolymorphismnoexcept

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


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?


Solution

  • 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.