はじめに
C++で、ファイルが存在しない、ネットワークがダウンしている、アクセス権がない、といったOSが原因のエラーを処理する場合、単なる int のエラーコードを返すだけでは、エラーの原因が何であるかが分かりにくくなります。
C++11では、このようなプラットフォーム依存のエラーを、移植性の高い、統一的な方法で扱うための仕組みとして、<system_error> ヘッダーが導入されました。
std::error_code: エラーコードの値とそのカテゴリ(どの種類のエラーか)をペアで保持する。std::system_error:error_codeをラップする例外クラス。
この記事では、これらのクラスを使って、OSレベルのエラーを型安全にハンドリングする方法を解説します。
【前提】C++11とは?
C++11は、2011年に正式化されたC++言語のメジャーアップデート版です。<system_error>ライブラリはこのC++11で導入されたため、利用するにはC++11以降に対応したコンパイラが必要です。
error_code / system_error を使ったサンプルコード
このコードは、データベースへの接続をシミュレートする関数を定義します。接続に失敗した場合、エラーの種類に応じて error_code を設定し、system_error 例外をスローします。
完成コード
#include <iostream>
#include <system_error> // error_code, system_error
#include <string>
using namespace std;
// データベース接続をシミュレートする関数
void connect_to_database(bool should_fail) {
if (should_fail) {
// 1. errc列挙体から、エラーコードを作成
error_code ec = make_error_code(errc::connection_refused);
// 2. error_codeをラップしたsystem_error例外をスロー
throw system_error(ec, "データベースに接続できませんでした。");
} else {
cout << "データベースへの接続に成功しました。" << endl;
}
}
int main() {
// 3. system_error例外をcatchする
try {
connect_to_database(true); // 失敗するケース
}
catch (const system_error& e) {
// 4. エラー情報を取得
const error_code& ec = e.code();
cout << "エラーが発生しました。" << endl;
cout << " 詳細: " << e.what() << endl;
cout << " カテゴリ: " << ec.category().name() << endl;
cout << " エラー値: " << ec.value() << endl;
cout << " メッセージ: " << ec.message() << endl;
}
return 0;
}
コードの解説
1. std::error_code
error_code は、エラーコードの値(int)と、その値がどのような種類のエラーなのかを示すカテゴリ(error_categoryへのポインタ)をペアで保持します。
error_code ec = make_error_code(errc::connection_refused);
std::errc:<system_error>で定義されている、移植性の高い標準的なエラー条件を表す列挙型です。errc::network_down(ネットワークダウン)やerrc::permission_denied(アクセス権なし)などがあります。make_error_code():errcの列挙子から、対応するerror_codeオブジェクトを簡単に作成するためのヘルパー関数です。
2. std::system_error
system_error は、std::exceptionから派生した例外クラスです。 throw system_error(ec, "追加メッセージ");
- 第1引数: エラーの原因を示す
error_codeオブジェクト。 - 第2引数(オプション): エラーに関する、より具体的な文脈を示す文字列。
3. try-catch ブロック
main関数では、system_error例外を catch しています。これにより、OSレベルのエラーが発生してもプログラムがクラッシュせず、エラー情報を分析して適切な対応をとることができます。
4. エラー情報の取得
catchブロックで捕捉したsystem_errorオブジェクト e から、様々な情報を取得できます。
e.code(): 元となったerror_codeオブジェクトを返します。e.what():system_errorのコンストラクタで渡された追加メッセージと、error_codeのメッセージを組み合わせた、詳細なエラー説明文字列を返します。ec.message():error_codeに対応する、プラットフォーム標準のエラーメッセージ(例:"Connection refused")を返します。
まとめ
今回は、C++11の <system_error> ライブラリを使って、OSレベルのエラーを扱うための標準的な方法を解説しました。
std::errc: 移植性の高い、共通のエラー条件を表す列挙型。std::error_code: エラーコードの値とカテゴリを保持する。std::system_error:error_codeをラップする例外クラス。
この仕組みを使うことで、ファイル操作やネットワーク通信などで発生しうる様々なプラットフォーム依存のエラーを、統一的で型安全な方法でハンドリングすることができます。
