問題の歴史:
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(); } }
重要な特徴:
デストラクタで例外をスローすることは許可されていますか?
いいえ、デストラクタで例外をスローするとスタックの展開中にstd::terminate()が呼び出されます。デストラクタ内での例外は、そのデストラクタ内部で捕捉する必要があります。
noexcept関数から例外をスローするとどうなりますか?
std::terminateが呼び出され、プログラムが異常終了します。noexceptは厳格な契約です。
値で例外を捕捉できますか?それはどのように危険ですか?
値で捕捉することは可能ですが、オブジェクトがコピーされます(object slicing)。const &を使用することを推奨します。
コード例:
try { throw std::out_of_range("err"); } catch (const std::exception& e) { /* ... */ }
リソースのデストラクタで例外をスローしていたコード; 異常終了時にスタックが正しく展開されず、リソースがリークしました。
長所:
短所:
重要なメソッドにはnoexceptが指定され、デストラクタは内部で全ての例外を処理しました。参照によるcatchが適用され、すべてのエラーがログされました。
長所:
短所: