C++における例外システムはtry-catchメカニズムとthrowキーワードに基づいています。例外的な状況(リソースエラーや不変条件の違反など)が発生した場合、tryブロック内でthrowオペレーターによって例外が発生します。適切なハンドラー(catch)を探す操作は、最初の一致する型までのスタックを示すことで行われます。
重要な詳細:
std::exceptionを基にしたクラス)。noexcept修飾子が導入されました。設計:
catch(const std::exception& e)。コード例:
#include <iostream> #include <stdexcept> void mayFail(bool fail) { if (fail) throw std::runtime_error("プロセスエラー"); } int main() { try { mayFail(true); } catch (const std::exception& ex) { std::cout << "キャッチした例外: " << ex.what() << std::endl; } }
デストラクタから例外がスローされた場合、他の例外がスタックを介して上に伝播しているとどうなりますか?
回答: 例外処理中に新しい例外を生成することは許可されていないため(ダブル例外)、std::terminate()が呼ばれ、プログラムが異常終了します。スタックのアンワインディングが損なわれます。
例:
struct CrashOnDestruct { ~CrashOnDestruct() noexcept(false) { throw std::runtime_error("デストラクタでのエラー!"); } }; void func() { CrashOnDestruct obj; throw std::logic_error("エラー処理"); } int main() { try { func(); } catch (...) { } } // std::terminate()で終了します
物語
大規模な金融アプリケーション内で、データベースのラッパークラスのデストラクタから例外がスローされていました。エラーが発生した場合の主要なトランザクションは例外を発生させ、アンワインド中にデストラクタが呼ばれ、再度エラーを投げました。アプリ全体が異常終了し、ユーザーの作業が失われました。開発者はデストラクタ内のthrowをログ記録と適切な処理に緊急で置き換えなければなりませんでした。
物語
マイクロサービスは、catch(std::exception)のように例外を処理していました。あるスレッドがユーザー定義型の例外(std::exceptionから継承されていない)をスローしていました。このようなエラーは捕捉されず、接続が予期せず切断され、メモリリークが発生しました。
物語
コンテナの移動メソッドでnoexcept修飾子が欠如していたため、標準ライブラリは高速なmove操作の代わりに遅いコピーを使用しました。パフォーマンスの重大な低下は負荷テストの時にのみ明らかになりました。