Programmingシステム開発者、バックエンド開発者

C++における未定義動作(undefined behavior)とは何ですか?それが危険な理由を教えてください。例を挙げて、その回避方法を説明してください。

Hintsage AIアシスタントで面接を突破

回答。

未定義動作(UB、undefined behavior)とは、コード内の動作が標準化されていない場合のことです。この場合、コンパイラは任意の決定を下すことができ、プログラムは異なるプラットフォームやコンパイラで異なる結果を出す場合もありますし、正式には核戦争を引き起こすことさえあります!UBの使用はC++における最も危険なエラーです。

UBの例:

  • 配列の境界を越えたアクセス
  • 初期化されていない変数の使用
  • 同じメモリ領域を二重に解放する
  • ダングリングポインタの使用
int* p = new int[2]; delete[] p; int x = p[1]; // UB: 解放後のメモリへのアクセス

UBを防ぐために:

  • 常に変数を初期化する;
  • 配列やコンテナの境界をチェックする;
  • 手動メモリ管理を避け、スマートポインタを使用する。

トリッキーな質問。

次のコードで何が起こりますか?

int a = 42; int b = a++ + ++a;

bの値は何になりますか?

回答:

このコードはUBを引き起こします。なぜなら、操作の間に順序点(sequence points)が無い状態で変数aを変更し、読んでいるからです。標準は特定の結果を保証せず、コンパイラは任意の結果を取得したり、予期しないコードを生成したりすることがあります。

このテーマの微妙な点を理解していないことによる実際のエラーの例。


物語 データストレージシステムのプロジェクトで、ある開発者が低レベルの関数で配列の境界を越えるアクセスを行いました。UBは特定のユーザーデータでのみ発生し、ファイル構造の破損やクライアントデータの損失を引き起こしました。


物語 マイクロコントローラ用のプロジェクトでは、初期化されていない変数の読み取りを伴う構造が見つかりました。テストは通過しましたが、デバイスのリリースから1年後にUBによるランダムなエラーが発覚しました:変数が時々ゴミ値を含んでいました。


物語 大規模なオープンソースプロジェクトで、異なるコードの部分から二重に解放されたディスクリプタが発見されました。最初は非常にまれにUBが現れましたが、新しいOSバージョンでは頻繁なクラッシュにつながるようになりました。