プログラムが異常した場合の処理をどのように記述してきたか?
C++以前の言語とC++以降の言語では
この辺りが大きく違うのではないでしょうか?
まあ、今回説明するExceptionと言うものの
元祖がC++なのか良く分かっていないのですが
私自身はC++で始めて出合った構文です。
この機能の素晴らしさはC言語プログラマであれば
絶対に分かる機能だと思います。
プログラムが異常した場合、終了させる方法は2つあります。
1つ目は「abort()」という手段で終わらせる方法
2つ目は「main」を正常復帰値以外で終わらせる方法です。
1つ目の方法は全てを破棄する方法ですから
特別な制御は不要です。
どのようなプログラムを作成するかによりますが
私自身はあんまり行わない終了方法です。
まあ私自身はオンラインプログラムが多く
しかもクラッシュさせる事が
絶対にできないシステム開発ばかりであったため
「abort()」という選択肢はありませんでした。
そのため必然的に2つ目の方法である
「main」の異常復帰という方法を取りました。
もちろん、データ不正などデータベース等にログしているデータが
不正の場合、続行は不可能です。
こういった場合、その影響範囲を最小にするための
制御としてクラッシュさせるわけにいかなかったと言う事です。
少し勉強した時はC言語の標準関数は「errono」に値を返す事を
利用してプログラムを組んだ時期もありましたが(こっちは趣味です)
基本的にはライブラリを使う人間としては
なぜライブラリの使用ができなかったのかというエラーは
あんまり重要ではない事がほとんどでした。
要するに、失敗したという事実が確認できれば十分であると言う事です。
そうなってくると「errono」の使用は少しづつ行う事をしなくなりました。
すると関数を呼び出し、その復帰値を参照し問題なければ次に。
また別の関数を呼び出し、また復帰値を参照し問題なければ次に。
という方法でプログラムを書く事が普通となります。
これは当り前なのですが、実はC言語では諦めている境地で
C++ではこんな方法はありえないと言う事になります。
例として制御関数「ctl_main()」が「int funcA()」「int funcB()」「int funcC()」
を呼び出ししているプログラムというものは
基本的には以下の通りになります。
int ctl_main() {
int nRet;
nRet = funcA();
if (nRet != 0) {
return nRet;
}
nRet = funcB();
if (nRet != 0) {
return nRet;
}
nRet = funcC();
if (nRet != 0) {
return nRet;
}
return nRet;
}
これは当たり前のようで物凄く読み辛いプログラムです。
異常系のロジックが半分以上埋め込まれている事がその原因です。
これをC++では以下の通りで表現する事ができます。
「void funcA() throw(string)」
「void funcB() throw(string)」
「void funcC() throw(string)」
int ctl_main() {
try {
funcA();
funcB();
funcC();
} catch(string e) {
cout << e << endl;
return -1;
}
return 0;
}
これは「funcA」「funcB」「funcC」が異常発生の時に
例外を「throw(発生させる)」するので、
異常系処理を行う必要がある場合に、
その例外を「catch(例外処理を行う事を宣言)」して
処理を行う。
例えば、あんまり良い例ではないが1例示します。
「funcA」「funcB」「funcC」が「引数:char」を取り、
以下の事をcheckする関数とします。
funcA:数字であるか判定
funcB:偶数であるか判定
funcC:3の倍数であるか判定
上記の3関数はCheck結果がNGとなる場合、例外を発生させます。
void funcA(char c) throw(string) {
if(('0' <= c) && (c <= '9')) {
} else {
throw string("Param is not Numeric.");
}
}
void funcB(char c) throw(string) {
if (c % 2) {
throw string("Param is not even.");
}
}
void funcB(char c) throw(string) {
if (c % 3) {
throw string("Param is not multiple of three.");
}
}
int ctl_main() {
try {
funcA();
funcB();
funcC();
} catch(string e) {
cout << e << endl;
return -1;
}
return 0;
}
これはthrowされた内容が出力されて異常終了する事になります。
この記述の優れているところは、
正常系処理の中に異常系処理を書く必要がなく
非常にプログラムが見やすいというところです。
次回は具体的な使い方を見ていきます。
0 件のコメント:
コメントを投稿