2018年01月09日
《その226》 例外の再送出
例外の再送出
捕捉した例外に応じた処理をした後で、「 throw; 」 と記述することにより、その例外を再送出することができます。
次のプログラムは、利用者に 501 〜 600 の素数を入力してもらい、それが本当に素数であるかどうかを判定するプログラムです。
◎ main関数から 関数(1)→ 関数(2)→ 関数(3)と呼び出しが連続して、
まず、関数(3)で、利用者に値を入力してもらいます。その際、関数(3)は、値を文字列として取り込みます。
◎ 関数(3)はその文字列を 関数(4)に渡して整数値に変換してもらいます。
関数(4)は、文字列に数字文字以外があれば、FormatError型の例外オブジェクトを送出します。
◎【関数(4)から、FormatError型の例外オブジェクトが送出された場合】
FormatError型例外オブジェクトは、関数(3)の例外ハンドラが受け取り、 "数字以外の文字が入力されました。" というメッセージを出力します。
関数(3)は、さらに、「 throw; 」文で、この例外を再送出します。
◎ 関数(2)と 関数(1)は、この FormatError型の例外オブジェクトを受け取ることのできる例外ハンドラを持っていません。この例外は、main関数の例外ハンドラが受け取り、"入力エラー発生!" を出力してプログラムが終了します。
◎【関数(4)から、無事に整数値に変換された値が 関数(3)に返却された場合】
関数(3)は、その値を 関数(2)に返却します。
関数(2)は、それが 501 〜 600 の範囲の数であるかどうかを調べ、範囲外であれば、ValueError型の例外オブジェクトを送出し、関数(2)は、自身の例外ハンドラでそれを受け取ります。そして、"不正な値が入力されました。" というメッセージを出力し、さらに、「 throw; 」文で、この例外を再送出します。
◎【関数(2)から、ValueError型の例外オブジェクトが再送出された場合】
関数(1)は、それをキャッチする例外ハンドラを持たないので、この例外は、main関数の例外ハンドラが受け取り、"入力エラー発生!" を出力してプログラムが終了します。
◎【関数(2)から、無事に、501 〜 600 の範囲の整数が、関数(1)に返却された場合】
関数(1)は、それが素数であるかどうかの判定をして、main関数に結果を返却します。
◎ main関数は、その結果を受けて、"確かに素数です!" または "素数ではありません!" と表示してプログラムが終了します。
※ 以上のように、離れた関数の結果を、例外という形で、main関数に伝えることができます。
main関数に、すべての例外を受け取ることのできる例外ハンドラを設置することで、プログラムの異常終了を回避することができます。
// ------------------------------------// ------------------------------------
#include <string>
#include <iostream>
using namespace std;
class FormatError { }; // 数字以外の文字が含まれているとき
// のエラー。
class ValueError { }; // 値が指定範囲外であるときのエラー。
// ◆(4) 文字列を int型の値に変換する関数
int string_to_int(const string& str) {
unsigned i = 0;
int n = 0; // 変換後の数値用の変数
int sign = 1; // 符号( 1 … 正, -1 … 負 )
while (isspace(str[i])) // 空白文字の読み飛ばし。
i++;
if (str[i] == '+') { i++; }
if (str[i] == '-') { i++; sign = -1; }
while (i < str.length()) {
if (!isdigit(str[i]))
throw FormatError();
// 数字以外の文字があれば、
// FormatError型の例外オブジェクトを送出。
n = n * 10 + (str[i] - '0');
i++;
}
return n *= sign;
}
// ◆(3) 値を読み込む関数
int get_val() {
int n = 0; // 整数値用の変数
string temp; // 入力文字列
try {
cin >> temp; // 文字列の読み込み
n = string_to_int(temp);
// 文字列をに関数 string_to_int に渡し、それを整数値
// に変換した値を受け取る。
return n; // 整数値を返却する。
}
catch (FormatError&) {
// 関数 string_to_int が送出した FormatError型の例外オブ
// ジェクトへの参照を捕捉。
cout << "数字以外の文字が入力されました。\n";
throw;
// 捕捉した FormatError型の 例外オブジェクトを再送出。
}
}
// ◆(2) 501 以上 600 以下の整数値であるかを調べる関数
int get_range() {
int n = get_val();
try {
if (n < 501 || n > 600)
throw ValueError();
// 501 以上 600 以下でなければ、ValueError型の例外オ
// ブジェクトを送出。
}
catch (ValueError&) {
cout << "不正な値が入力されました。\n";
throw;
// 捕捉した ValueError型の 例外オブジェクトを再送出。
}
return n;
}
// ◆(1) 素数であるかどうかを判定する関数
bool prime_num() {
int n = get_range();
// get_range関数から、501 以上 600 以下の整数を受け取る。
bool b = true;
for (int i = 2; i <= n / i; i++) {
if (!(n % i)) { b = false; break; }
}
return b;
// n が素数なら b は true, 素数でなければ false になる。
}
int main() {
cout << "501 以上 600 以下の素数を入力 : ";
try {
if (prime_num()) cout << "確かに素数です!\n";
else cout << "素数ではありません!\n";
}
catch (...) {
cout << "入力エラー発生!!\n";
}
}
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/7178172
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック