ProgrammingC++ システムプログラマー

C++における例外(exceptions)の動作メカニズムについて教えてください。エラーを正しく処理する方法とnoexceptの目的は何ですか?

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

回答。

問題の歴史:

C++では、エラー処理のために例外処理メカニズムが導入され、リターンコードに比べてより信頼性と構造的なエラー処理が実現されました。年月が経つにつれて、構文は拡張され、関数からの例外のスローを制御するためのnoexcept型指定子が登場しました。

問題:

例外を不適切に扱うと、メモリリーク、未定義動作、アプリケーションのクラッシュを引き起こすことがあります。コンストラクタ、デストラクタ、またはリソースの操作からの例外スローを考慮しないと、プログラムの状態に深刻な問題が発生します。

解決策:

基本的な構文は、try-catchの使用です。例外は任意の型になる可能性がありますが、カスタム例外はstd::exceptionから派生することを推奨します。キーワードnoexcept(C++11+)は、関数が例外をスローしないことを示し、noexcept関数から例外をスローするとstd::terminate()が呼び出されます。

コード例:

#include <iostream> #include <stdexcept> void func() noexcept(false) { throw std::runtime_error("Error!"); } int main() { try { func(); } catch(const std::exception& ex) { std::cout << ex.what(); } }

重要な特徴:

  • 例外は自動的なスタックアンワインドを提供します。
  • noexceptは、関数が確実に例外をスローしない場合にコンパイラが最適化を行えるようにします。
  • std::exceptionとその派生のみがwhat()メソッドの存在を保証します。

裏の質問。

デストラクタで例外をスローすることは許可されていますか?

いいえ、デストラクタで例外をスローするとスタックの展開中にstd::terminate()が呼び出されます。デストラクタ内での例外は、そのデストラクタ内部で捕捉する必要があります。

noexcept関数から例外をスローするとどうなりますか?

std::terminateが呼び出され、プログラムが異常終了します。noexceptは厳格な契約です。

値で例外を捕捉できますか?それはどのように危険ですか?

値で捕捉することは可能ですが、オブジェクトがコピーされます(object slicing)。const &を使用することを推奨します。

コード例:

try { throw std::out_of_range("err"); } catch (const std::exception& e) { /* ... */ }

一般的なエラーとアンチパターン

  • デストラクタでthrowを使用すること
  • ロギングなしにcatch(...)で例外を飲み込むこと
  • 可能な場所でnoexceptを指定しないこと

実生活の例

ネガティブケース

リソースのデストラクタで例外をスローしていたコード; 異常終了時にスタックが正しく展開されず、リソースがリークしました。

長所:

  • エラーを迅速に検出できる可能性があります。

短所:

  • プログラムはしばしばterminateエラーで終了しました。

ポジティブケース

重要なメソッドにはnoexceptが指定され、デストラクタは内部で全ての例外を処理しました。参照によるcatchが適用され、すべてのエラーがログされました。

長所:

  • 信頼性、リークなし
  • 極めて予測可能な動作

短所:

  • 開発者に対して「クリーンな」コードを記述する際の厳格さが増しました。