【C++】std::exceptionの概要と使い方【標準ライブラリ】
std::exceptionとは
`std::exception` は C++ の標準ライブラリに含まれる例外の基底クラスです。 すべての標準例外クラスは `std::exception` を継承しており、独自の例外クラスを作成する際にも継承できます。 `std::exception` は以下のような基本的な機能を持っています。
class exception {
public:
virtual const char* what() const noexcept;
};
`what()` メソッドは、例外の説明をC文字列として返すメソッドです。 標準ライブラリの例外は、このメソッドをオーバーライドしてエラーメッセージを提供します。
基本的な使い方
`std::exception` の基本的な使い方を見てみましょう。
#include <iostream>
#include <exception>
int main() {
try {
throw std::exception();
} catch (const std::exception& e) {
std::cout << "例外が発生: " << e.what() << std::endl;
}
return 0;
}
`std::exception` の `what()` メソッドは `"std::exception"` という文字列を返します。 実際のエラー内容を提供するには、派生クラスを利用するのが一般的です。
派生クラス
C++標準ライブラリには、`std::exception` を継承したいくつかの例外クラスが用意されています。
std::logic_error
: プログラムのロジックエラーstd::runtime_error
: 実行時エラーstd::bad_alloc
: メモリ確保の失敗std::bad_cast
: 型キャストの失敗std::out_of_range
: 範囲外アクセス
#include <iostream>
#include <stdexcept>
int main() {
try {
throw std::runtime_error("実行時エラーが発生しました");
} catch (const std::exception& e) {
std::cout << "例外: " << e.what() << std::endl;
}
return 0;
}
独自の例外クラスの作成
`std::exception` を継承して独自の例外クラスを作成することも可能です。
#include <iostream>
#include <exception>
class MyException : public std::exception {
public:
const char* what() const noexcept override {
return "独自の例外が発生しました";
}
};
int main() {
try {
throw MyException();
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
return 0;
}
例外安全性
C++では、例外の発生時にリソースリークが起こらないように注意する必要があります。 そのために、RAII(Resource Acquisition Is Initialization)を活用するのが一般的です。
#include <iostream>
#include <memory>
#include <exception>
class Resource {
public:
Resource() { std::cout << "Resource 確保\n"; }
~Resource() { std::cout << "Resource 解放\n"; }
};
int main() {
try {
std::unique_ptr res = std::make_unique();
throw std::runtime_error("エラー発生");
} catch (const std::exception& e) {
std::cout << "例外キャッチ: " << e.what() << std::endl;
}
return 0;
}
例外の伝播と再送出
例外は関数の外に伝播させることもできます。
void func() {
throw std::runtime_error("関数内で発生した例外");
}
int main() {
try {
func();
} catch (const std::exception& e) {
std::cout << "例外をキャッチ: " << e.what() << std::endl;
}
}
例外処理のベストプラクティス
- 例外はできるだけ `std::exception` の派生クラスを使う
- RAIIを活用して、例外発生時のリソース管理を適切に行う
- 例外はキャッチしたら適切に処理し、むやみに握りつぶさない
- 例外は「異常な事態」のみに使用し、通常の制御フローには使わない