C++ の標準例外安全規則と強い保証
この前、 Exceptional C++ 読んだ時にメモしておこうと思って忘れてたので今度こそ。
例外安全における重要な保証
- 基本的な保証 : リソースをリークしないこと。
- 強い保証 : 例外発生前の (参照やイテレータといった) プログラムの状態にロールバックできること。
- nothrow 保証 : 完全に例外を投げないこと。とくにデストラクタや swap 関数はこれが必要。
標準例外規則
- デストラクタ・
operator delete
は例外を投げない。つまりthrow()
を指定すること。(補足:C++11以降はnoexcept
キーワードを使うとわかりやすい) - RAII イディオムを常用し、リソースの所有と管理を分離すること。
- 例外を投げる可能性がある箇所(リソース確保、コピーなど)を全て、別個の関数で安全に処理すること。
以上は「例外安全」の説明です。これとは別に「例外中立」という概念もあります。それぞれの定義は
- 例外安全 : 例外が発生しても適切に処理する (メモリリーク無し、例外発生前と一貫性を保つ = ロールバックする)
- 例外中立 : 全ての例外を呼び出し側に伝える (捕捉して握りつぶさない)
例外中立を実現するには try/catch を除去するリソース管理の技法(copy&swapなど)が紹介されています。なお、例外安全と例外中立は、標準ライブラリのコンテナに保証される性質です。この本は例外処理以外にもいろんな規則 (Liskov Substitution Principle とか) やイディオム (pimpl とか) がでてきて、いかに C++ が複雑な言語か思い知らされる本です。補足として、現在ではこの本の中心となる nothrow 保証な swap 関数を実装する他に move semantics を利用する手もあります。