例外ネタでもうひとつ。
ま、そゆわけで例外投げるときゃ「誰がコケたか」じゃなく「なぜコケたか」がわかる例外投げようね、と。
もひとつのキモは「ちゃんと階層化しようゼ」です。
class おなかイタイ {};
class あたまイタイ {};
class あたまワルイ {};
class 電車止まってる {};
class コムギコカナニカダ {};
class 俺の妹がこんなに可愛いわけがない {};
なんて横並びに例外こしらえちゃうとcatch側がいい迷惑で:
try {
Person p = 会社.人よこせ();
} catch ( おなかイタイ& ) {
...
} catch ( あたまイタイ& ) {
...
} catch ( 電車止まってる& ) {
...
}
なんてなcatch節をあーでもないこーでもないと並べにゃならんす。
try {
Person p = 会社.人よこせ();
} catch ( 個人の問題& ) {
おしおきだキサマ
} catch ( 外的要因& ) {
それじゃ仕方ないねー
}
とか書けるように継承関係でカテゴライズしましょうね、と。
標準C++では ヘッダ<stdexcept>に例外用基底クラスがいくつか定義されてます:
exception : <exception> で定義された例外の総本山
logic_error : 「そんなんじゃ仕事できんよ」的な
domain_error : 領域/分野 (後述)
invalid_argument : 「おかしな引数もらった」
out_of_range : 「想定の範囲外」配列の上限超えてるとか
runtime_error : 「仕事したらヘンな結果でちゃった」的な
overflow_error : デカくなりすぎた
underflow_error : ちっさくなりすぎた
range_error : 想定された範囲に収まらなんだ
で、わしらが例外投げるとするとこの階層のどっから導出するかなんだけども、どうやらdomain_errorてのが領域/分野に特化したエラーてことで、アプリケーションあるいはそれに近いレイヤから投げるものはdomain_errorから導出するんが妥当なセンのようです。
あるいはruntime_errorあたりから。せめてexceptionじゃないと前述の「あーでもないこーでもない」を利用者に強いることになります。
# 最悪 catch (...) で捕まえられるけど肝心の「なぜコケた」がわからずじまい。
[追記] コメントで突っ込まれました。
「domain_error」のdomainは「領域/分野」じゃなくて、数学でいう「定義域」ちゃうんかい、と。
あーなるほど、 domain_error=定義域の外 と解釈すれば logic_error の派生であるのに納得できますし、runtime_erroから導出されたrange_error=値域の外 との対応がつくです。
# だったら out_of_range は out_of_domain がせーかいちゃうんかの ^^;
なので訂正。
で、わしらが例外投げるとするとこの階層のどっから導出するかなんだけども、この基準に合わせるかぎり、「ヘンなもんもらったので門前払い」ならlogic_error,「ヘンな結果こしらえたので引責辞任」ならruntime_errorあたりが妥当なセンのようです。