導入
C++ には、用途別の標準例外クラスが用意されています。自分で投げるときも受けるときも、これらを土台にすると分かりやすくなります。あわせて「例外が起きても壊れない」コードの考え方に触れます。
この回は読み物です(例外の送出を含むため)。コードは手元の環境(g++ / clang など)で試してください。
説明
標準例外はすべて std::exception を親に持ち、<stdexcept> によく使うものがそろっています。catch (const exception& e) と親で受ければ、種類を問わずまとめて捕まえられます。
flowchart TB E["std::exception(すべての親)"] E --> L["logic_error<br/>(プログラムの論理ミス)"] E --> R["runtime_error<br/>(実行時の問題)"] L --> IA["invalid_argument"] L --> OR["out_of_range"] R --> OF["overflow_error"]
#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;
int main() {
vector<int> v = {1, 2, 3};
try {
cout << v.at(10) << endl; // at は範囲外で out_of_range を投げる
} catch (const out_of_range& e) {
cout << "範囲外: " << e.what() << endl;
} catch (const exception& e) { // それ以外の標準例外もまとめて
cout << "その他: " << e.what() << endl;
}
return 0;
}
catch は上から順に試され、最初に合ったものが使われます。より具体的な型を上、const exception& を下に置くのが定石です。前章のスマートポインタや vector を使っていれば、例外で途中脱出しても資源は自動で解放されます(これが「例外安全」の土台)。
まとめ
標準例外は std::exception を頂点とする階層で、<stdexcept> の out_of_range などを使います。catch は具体的な型を上・const exception& を下に。RAII(スマートポインタ・vector)を使えば、例外が飛んでも資源が漏れない「例外安全」なコードになります。