C++26、無限ループを未定義動作から救う

C++26: Trivial infinite loops are no longer undefined behaviour

C++ではwhile(true);のような無限ループが未定義動作とされ、Clangはループを削除してリンカが配置した関数を実行することがあった。C++26のP2809R3は、本体が空で制御式が定数trueの「自明な無限ループ」を明確に定義し、std::this_thread::yield()呼び出しに置き換える。組み込みやカーネルで使われる停止パターンの安全性が向上する。

C++26はこれをP2809R3で修正する。自明な無限ループはもはや明確に定義される。
  1. JoshTriplett

    > 両方の条件が満たされると、ループ本体は std::this_thread::yield() の呼び出しに置き換えられる。

    ここで叫び声を上げてください。

    ライブラリ呼び出しが一切ない無限ループに、システムコールが挿入される。それは待ち受ける恐ろしい驚きだ。

    「forward progress guarantee」という概念全体が壊れている。無限ループは無限ループにコンパイルされるべきだ。それ以上でもそれ以下でもない。

  2. omoikane

    > ループは自明に空の反復文でなければならない -- つまりその本体は文字通り空である

    これはループ本体が「continue」であってはならないと言っているように思える。実際、-std=c++26 で ";" を試したところ、約束通り無限ループになったが、"continue" では未定義動作が復活する:

    - "while(true);" -> https://godbolt.org/z/T65o51crx

    - "while(true) continue;" -> https://godbolt.org/z/Pj9raEcnP

    これは残念だ。なぜなら、単一のセミコロンよりも "continue" を好むスタイルガイドを一つ知っているからだ。おそらく、そうしたコードは今後すべて "while(true) {}" になるだろう。

    https://google.github.io/styleguide/cppguide.html#Formatting...

  3. Aurornis

    あの例で unreachable() 関数が実行されるとは全く予想していなかった。実際には遭遇しないだろうが、#ifdef の層で奇妙なことが起こるのは見たことがある。

  4. wahern

    > 両方の条件が満たされると、ループ本体は std::this_thread::yield() の呼び出しに置き換えられる。これにより、ループの実行に以前は欠けていた forward-progress セマンティクスが与えられる。

    これは、Linus や他の多くの人々が C++ について嫌う隠れたコードの欠点の典型例だ。コンストラクタとデストラクタについては、ある程度避けられず、それほどランダムではないが、Rust は少なくともドロップの場合において、非ローカルコードの影響範囲を制限するのが上手い。

    もし C11 のルールを採用したくなかったのなら、C++ 委員会は、自明なループ(C11 で定義されているか否かに関わらず)に対してコンパイラが診断またはエラーを出すことを要求し、プログラマに明示的に ::yield などを挿入させるルールを検討すべきだった。隠れたコードはなく、コンパイラが予想外のことをする機会も減る。

    C 委員会は、標準で UB ケースを厳密に列挙し、多くの場合、診断やエラーを要求するか、実装定義の動作に変えることで、各ケースに順番に対処してきた。しかし、そのようなコードを挿入することは考えられない。

  5. peterus

    マイクロコントローラプログラミングにおいて、無限 while(1) ループには有効なユースケースがある(一般通念に反するようだが)。stm32 用の自動生成 HAL コードはエラーハンドラにこれを使い、C++ もサポートしているので、これが UB だったのは驚きだ。

    私はエラーハンドリングにしか使わないし、もちろん電力に敏感なアプリケーションで待機/ストールにこれを使うのは悪い考えだ。その場合は割り込みからのウェイクアップを使うべきだ。

    余談だが、私はエラーハンドラにソフトウェアブレークポイントを入れるのが好きだ。ハードウェアブレークポイント(マイクロコントローラによって物理的に制限される)を無駄にせず、デバッグが容易になる:

    __BKPT();

    while (1)

    ;

この日のほかの記事

2026-09-18