> (つまり関数内でローカルに定義されるオブジェクトへの参照というのが、
> なんとなく引っかかる。(^^;)
catch節の参照は、呼出先関数のローカル変数への参照ではありません。
throwによって投げられたオブジェクトは、例外処理機構内にコピーされており、
そのコピーされたオブジェクトへの参照を受け取ります。
(例外処理機構内にコピーされたオブジェクトのスコープは、
try/catchの終わりまでになります)
こういうのは最も信頼の置ける文献すなわち IS を見ましょう。
# international standard : ISO/IEC 14882:1998
標準 C++ の投げる例外は std::exception の派生クラスです。
んで std::exception はこんな感じ。
namespace std の中で
class exception {
public:
exception() throw();
exception(const exception&) throw();
exception& operator=(const exception&) throw();
virtual ~exception();
virtual const char* what() const throw();
};
new 失敗時に投げられる例外は std::bad_alloc で、当然 std::exception 派生クラス。
つーことできっちり設計された例外クラスをうまく使えば
catch (const std::exception& ex) {
std::cerr << ex.what() << std::endl;
}
だけでよかったりします。
what() が virtual なのが味噌なのね。
exception() throw() の throw() は例外指定って奴で、
この場合「このコンストラクタは例外を投げない」の意味になります。
# 例外処理中に例外を投げちゃうと話がややこしいのだ。
> 本末転倒しないように注意が必要です(^^;
むっちゃ御意。
> throwによって投げられたオブジェクトは、例外処理機構内にコピーされており、
> そのコピーされたオブジェクトへの参照を受け取ります。
なるほど! 完璧に納得がいきました。(^^) ありがとうございます。m(__)m
> この場合「このコンストラクタは例外を投げない」の意味になります。
> # 例外処理中に例外を投げちゃうと話がややこしいのだ。
なるほど…。この方法でコンストラクタは例外を投げないということを
明示しているんですね。(^^)
…ということで、割り込みをかましちゃいましたが、
重ね重ねありがとうございます。
これまで不安に思っていた部分ですが、非常に納得がいきました。
> しかし、実際には私自身もここまで階層分けしたことはありません。
> クラスを分けるのはエラー処理を分けたいからですが、
> エラー処理って殆どの場合、エラーメッセージを出して処理を中断するだけですし…。
>
> 例外を使って処理分岐なんてのに凝りだすと、
> それは例外処理ではなくて単なる正常系の分岐処理になってしまいますので、
> 本末転倒しないように注意が必要です(^^;
ですよね~。
catch ブロックを中心にモノを考えるとよいかしら?
1.エラー後処理のしたいとこに catch ブロックを書く
2.そこで catch したいエラーの種類を洗い出し、対応した例外クラスを定義
3. 2. で定義したエラーが発生すると予想されるとこを try でくくる
あまりたいしたポリシーでもないけど、今後はこれでいきます。
一応解決とさせていただきます。
ありがとうございました>発言者の皆様方。
かいけつちぇっく
解決マークが入っていないので蛇足などしてみましょう。
俺的意見なのでそれ以上のものを求めないでください。
Q1:なにか失敗したとき、エラーを返却するか例外送出にするか?
A1-1:一般常識的に起こりうる失敗はエラー返却。ヤバイ系失敗は例外送出。
例:仮想記憶の使えるマシン/OS で malloc() 失敗は非常事態なので例外
例:open しようとしたファイルが無いとかはエラー返却。
A1-2:閉じた世界で処理都合的に便利なら例外を積極的に使おう
ただしその場合、上位ルーチンに例外を漏らさないのが鉄則。
例:データベースの transaction 更新中に失敗という状況を想定
・更新ルーチンの中では try/catch/throw を使う
→エラー対処をたまたま入れ忘れた場所でデータベースを壊すのが怖い
ならいっそ積極的に throw を使うべきだ。
throw さえされれば catch に戻ってくるのだからそれなりの対処ができるはず。
・更新ルーチンそのものは失敗値を返却
→リトライするのは上位アプリの仕事だから
上位ルーチンは C++ で作られてないかもしれない。上位ルーチンが例外を受け取らずに
データベース開きっぱなしのまま異常終了、なんてのは絶対避けたい。
Q:try/catch の入れ子は?
A:何らかのチェックポイントで try/catch すればそれでいい。
チェックポイントに戻りたいところで throw
チェックポイントが処理階層で複数個あるのはごく普通の状況だと思う。
要は例外を垂れ流しにするのが良くないのであって、きっちり後始末するなら
積極的に使ってもいいんぢゃないのかな?
自分の組んでるルーチンが発生させる例外はすべて自分で処理する、ってのが
最低限の約束だと思う。
リアルタイムな処理では例外処理にかかる時間の予測ができないとかあるから
そーいうところでは使えないですが。