noexcept のコード生成への驚くべき影響

noexcept をスパムするかどうか キーワードでコードを高速化しますか?時々。しかしいつもではない。次のコード スニペットを検討してください:

int g();

int f() {
  return g();
}

g は意図的に定義していません そうしないと、コンパイラが賢すぎてすべてをインライン化するため、この翻訳単位では. それにもかかわらず、すべての主要な C++ コンパイラは f g への末尾呼び出しのみが含まれています 次のようなコードを生成します:

f():
        jmp     g()

次のコードを考えてみましょう:

int g();

int f() noexcept {
  return g();
}

コンパイラは g かどうかわからないので スローするかどうかに関係なく、std::terminate を呼び出すコードを生成する必要があります。 悪いことが起こった場合に備えて.さまざまなコンパイラからのコード生成の結果は次のとおりです:

msvc

$ip2state$int f(void) DB 02H
        DB      08H
        DB      00H
$cppxdata$int f(void) DB 060H
        DD      imagerel $ip2state$int f(void)

int f(void) PROC                                      ; f, COMDAT
$LN5:
        sub     rsp, 40                             ; 00000028H
        call    int g(void)                         ; g
        npad    1
        add     rsp, 40                             ; 00000028H
        ret     0
int f(void) ENDP                                      ; f

gcc

f():
        sub     rsp, 8
        call    g()
        add     rsp, 8
        ret

クラン

f():
        push    rax
        call    g()
        pop     rcx
        ret
        mov     rdi, rax
        call    __clang_call_terminate
__clang_call_terminate:
        push    rax
        call    __cxa_begin_catch
        call    std::terminate()

C 関数の扱い方

これで noexcept であることがわかりました 内部で noexcept 以外の関数を呼び出すとオーバーヘッドが発生する可能性があります。スローしないが noexcept としてマークされない関数をどのように処理しますか? ?幸いなことに、尊敬すべきハナ・ドゥシコバが賢い解決策を思いつきました:

noexcept_cast をマークできます 関数はコンパイラ固有の拡張機能によって強制的にインライン化されるため、デバッグ モードでのパフォーマンスが低下しません。

結論

noexcept をスパムしないでください プロジェクトごとの「例外なし」ポリシーがない場合。また、ユーザー定義関数を呼び出す可能性のある高階関数には特に注意してください。全体として、noexcept 型システムの一部であり、API のコントラクトです。 noexcept のみ追加 スローしないことを保証したい関数に。