例外機構を考察するスレ
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2009/08/10(月) 10:57:51例外さんについて語ってください。
(言語は問わない)
0002デフォルトの名無しさん
2009/08/10(月) 11:00:29言語訓練のために立てたものです。
アイと研究員とのやり取りに利用するスレッドなので、
関係者以外は書きこまないで下さい。
京都大学霊長類研究所
0003デフォルトの名無しさん
2009/08/10(月) 11:13:08try { } catch(...) { } finally { }
だよな。SEHでは:
__try { } __except(...) { }
__try { } __finally { }
となる。
0004デフォルトの名無しさん
2009/08/10(月) 11:16:44Try/Catchブロックが使えるようになった。
0005デフォルトの名無しさん
2009/08/10(月) 11:18:53ということに注意。
0006デフォルトの名無しさん
2009/08/10(月) 11:20:48変えることがある。
__TRY { } __EXCEPT(...) { }
__TRY { } __FINALLY { }
0007デフォルトの名無しさん
2009/08/10(月) 11:47:370008デフォルトの名無しさん
2009/08/10(月) 12:37:380009デフォルトの名無しさん
2009/08/10(月) 13:14:24実際に例外を投げた場合に、プログラムの状態が壊れずリソースも
リークしないように作るプログラミングのことを言います。
http://www.kmonos.net/alang/d/2.0/exception-safe.html
0010デフォルトの名無しさん
2009/08/10(月) 13:16:48オブジェクトが更新途中の中途半端で不完全な内部状態のままになったりせず、
呼び出し前の正常な内部状態に戻る性質
0011デフォルトの名無しさん
2009/08/10(月) 16:05:520012デフォルトの名無しさん
2009/08/10(月) 17:06:54どうしてもやらなきゃならない場合は
例外を握りつぶしても例外安全になるように作る。
ミスが入りやすいし手間がかかるから、極力やらないど。
0013デフォルトの名無しさん
2009/08/10(月) 18:27:320014デフォルトの名無しさん
2009/08/10(月) 19:08:49外に書いたコードより低速でメモリ使用も膨れるの?
0015デフォルトの名無しさん
2009/08/10(月) 19:39:200016デフォルトの名無しさん
2009/08/10(月) 19:40:43かからない実装もある
中が外より遅いとかってことはないはず
0017デフォルトの名無しさん
2009/08/10(月) 19:59:550018デフォルトの名無しさん
2009/08/11(火) 07:22:47C++にfinallyはないよ
0019デフォルトの名無しさん
2009/08/11(火) 07:38:50http://www.artima.com/intv/handcuffs2.html
> That is not the important thing about exceptions.
> In a well-written application there's a ratio of ten to one,
> in my opinion, of try finally to try catch.
リンク集
http://en.wikipedia.org/wiki/Exception_handling#External_links
0020デフォルトの名無しさん
2009/08/11(火) 08:09:190021デフォルトの名無しさん
2009/08/11(火) 11:18:13GC 完備の言語だと destructor でリソース廃棄ってのをしにくいから
finally がいるかもしらんが、C++ だと普通スコープを抜ければ
finally がなくても自動的に dtor で話が済むと思うのだが...
0022デフォルトの名無しさん
2009/08/11(火) 13:08:35> GC 完備の言語だと destructor でリソース廃棄ってのをしにくいから
GCありでRAIIってまずいの?
もしリソース解法タイミングの遅延を問題にしているのなら、
C#でもIDispopsable + usingで解決するけど…他にもなにかあるのだろうか?
0023デフォルトの名無しさん
2009/08/11(火) 13:31:09インターフェース内のネストクラスとして例外クラスを提供して
それ以外の例外は絶対に投げない
(標準の例外もBadAllocといった感じでラップする)
といった感じでやってるんだが
もっといいやり方はないんだろうか
0024デフォルトの名無しさん
2009/08/11(火) 14:22:19遅延したデストラクタ内で発生した例外は誰が受け取るの?
0025デフォルトの名無しさん
2009/08/11(火) 14:27:280026デフォルトの名無しさん
2009/08/11(火) 14:44:09RAII使ってたらその必要に迫られることがある。
0027デフォルトの名無しさん
2009/08/11(火) 14:58:44RAIIは解放を全自動化できる魔法の弾丸じゃないのだから、
処理用の関数を用意しておいてそれを呼んで資源解放すれば良い。
なぜこうするのか。
デストラクタから例外が投げられた場合、
C++ならterminateされる場合もあるし未定義の動作の原因となる。
C++以外でも破壊が中途半端に終わり壊れたオブジェクトになる。
あと、Disposeから例外を投げた場合も同様に壊れたオブジェクトになるよ。
0028デフォルトの名無しさん
2009/08/11(火) 21:01:16RAIIを使って、資源の確保はオートマチックな感じにやるけど
解放は手動でやれ、ってこと?
0029デフォルトの名無しさん
2009/08/11(火) 21:38:13例外が発生するような解放処理なら、手動でやらなきゃならない。
例えば、例外が発生してローカル変数のデストラクタが呼ばれ
ローカル変数のデストラクタで例外を発生させたら、C++なら即死する。
たとえ即死しなくても、デストラクタ中から例外を投げたら
その後の処理が(多くの場合、その親クラスのデストラクタすら)実行されず危険。
デストラクタでは例外が発生してもその場で即時握りつぶす以上はできない。
0030デフォルトの名無しさん
2009/08/11(火) 22:26:51まともな本ならちゃんと書いてある
どうしても例外起こる可能性のある処理をするなら
例外を握りつぶしてからエラーログを吐くなりなんなりする
0031デフォルトの名無しさん
2009/08/12(水) 00:49:44badallocになった時って、例外用のインスタンスって生成できる?
0032デフォルトの名無しさん
2009/08/12(水) 01:36:37メモリ確保なしでできることしかできない=何もできない。
システムがプログラムを落としてくれることを願う以上は実質何もできない。
0033デフォルトの名無しさん
2009/08/12(水) 02:15:030034デフォルトの名無しさん
2009/08/12(水) 10:15:19bad_alloc 用のメモリを残してくれている可能性もあるし、そうでない可能性もある
昔 GCC でやったら、小さいメモリの確保に失敗した時はプログラムが強制終了されたな
terminate だったのかそうでないのかは忘れたが
どちらにしろ、ギリギリ bad_alloc できたとしても、
catch 内で出来る事はすくないんだけどね・・・
0035デフォルトの名無しさん
2009/08/12(水) 12:42:28それはgccというかLinuxでの挙動じゃないか?
SIGKILを送りつけられてしまうから、問答無用、terminateなしで殺される
0036デフォルトの名無しさん
2009/08/12(水) 12:47:29それを回避するには、楽観的メモリ確保戦略を禁止しないといけない。
0037デフォルトの名無しさん
2009/08/12(水) 20:36:46>>34 とは違う
0038デフォルトの名無しさん
2009/10/17(土) 01:30:58class Parent {
protected virtual void doInner() = 0;
public void do() { ...色々... doInner(); ...色々... }
}
class Child : public Parent {
private void doInner() { ...例外を投げるかもしれない処理... }
}
Parent::Doは当然の事ながらChild::doInnerの投げる例外は知らないわけで
・Parent::doでは、全例外を無差別に掴んで後処理する。
→メモリ不足等まで握りつぶして危険
・Parent::doで後処理したら、必ずそのまま再スロー
→Parent::doを呼ぶクラスが困る。
Parent::doから外に投げられる例外が分からないから。
・Child::doInnerから例外を投げないように注意して作ってもらう or 投げてよい例外を規定する
→派生クラス側で間違えたらNG。
と、どこかで破綻する気が。
0039デフォルトの名無しさん
2009/10/17(土) 02:59:38要するに、投げてよい例外を規定しなければならないタイプの例外と、
規定しなくてよい (規定するのが難しい) 例外があるってこと。
0040デフォルトの名無しさん
2009/10/17(土) 04:35:22例外の前にコンパイルエラーになるから安心しろ。
0041デフォルトの名無しさん
2009/10/17(土) 04:47:21設計時の問題だと思うんだけど。
子クラスが親クラスの知らない例外を投げること自体は必要だという前提でいいんだよね?
なら、それをどこでハンドリングするかというのも考慮してあるはずじゃないかな。
あと、
> ・Child::doInnerから例外を投げないように注意して作ってもらう or 投げてよい例外を規定する
のときの
> →派生クラス側で間違えたらNG。
はアサーションでいいでしょ。
破綻するなら、ハリウッドの原則な設計を採用したことが間違いだったんだよ。
0042デフォルトの名無しさん
2009/10/17(土) 09:22:040043デフォルトの名無しさん
2009/10/18(日) 03:39:58>>39,40
Javaならそれでいい(必要なものを宣言すればいい)のですが、C#は例外仕様を書くことすらできず、
C++は例外仕様を書いてもコンパイラではチェックせず動作中に違反すると即落ちてしまいます。
# C++の奴は、実質"OffにできないAssert"という地雷で"使用するな"としている書籍も多数
>>41
> 子クラスが親クラスの知らない例外を投げること自体は必要だという前提でいいんだよね?
> なら、それをどこでハンドリングするかというのも考慮してあるはずじゃないかな。
前提はそうです。が、親子だけで例外をどっちで掴むかしか考えていませんでした。
全体でハンドリングを考えてみると、
「子に親の知らない例外を投げさせる事自体禁止する」か、
「(親の利用者が子も知っている前提なら)利用者が子の投げた例外を掴む」か、
「子が投げる例外は、誰も掴まない」か、ぐらいから選ぶしかなさそうですね。
ちょっと全体設計を見直してみます。
> はアサーションでいいでしょ。
それが一番簡単で確実そうですね。
0045デフォルトの名無しさん
2009/10/18(日) 16:20:38ttp://en.wikipedia.org/wiki/Hollywood_Principle
0046デフォルトの名無しさん
2009/10/23(金) 12:45:15ネイティブアーキテクチャを変える時ってほんと好き放題やれるよな
0047デフォルトの名無しさん
2009/11/28(土) 15:47:57アホって事?
0048デフォルトの名無しさん
2009/11/28(土) 23:13:470049デフォルトの名無しさん
2009/11/29(日) 00:46:59tryの用法には「非標準的な実行エラー(想定した状況から逸脱した状況)をどこかで集中的に対処」と
「finallyでリソース解法」の二種類があり、それらは書式が同じだけで中身は全くの別物。
前者が大量にあるのなら使い方/設計が正しいかを疑うべき。
例外処理を集約できていなかったり、処理できないのにcatchしてたり、例外にすべきでないものを例外にしている可能性がある。
後者が大量にあるのならそれ自体は例外処理としては問題ではない。
ただ、別な問題としてリソース解法漏れにならぬようRAII型導入を考えたほうがベター。
かく言う俺も会社の方針で「Assert禁止。代わりに例外投げろ」なんて
やっているから実行エラーもバグも混在してヒドいことになっているがw
0050デフォルトの名無しさん
2009/11/29(日) 00:55:14そうじゃなくて、tryを書くことで実行時のオーバーヘッドが大きいかどうか
という話かと。
0051デフォルトの名無しさん
2009/11/29(日) 01:10:54そうなの?
不要なtryをやたらと書く、例えば「あちこちに大量にtryを書いてログを取る」とか、そのレベルの話かとオモタ
0052デフォルトの名無しさん
2009/12/03(木) 13:42:16それは処理系によるとか言えんよな
gccでも例外発生時は遅いけど実行時のオーバーヘッドは0のと、例外発生時も早いけど一定のオーバーヘッドがある2系統選べるし
0053デフォルトの名無しさん
2010/03/05(金) 08:36:260054デフォルトの名無しさん
2010/03/05(金) 22:41:190055デフォルトの名無しさん
2010/03/06(土) 01:56:38特にC++だとやっかい。
0056デフォルトの名無しさん
2010/03/06(土) 12:08:080057デフォルトの名無しさん
2010/03/06(土) 13:13:26f(){
a();
....
a();
}
どちらのaを呼んだかとかをさ
f(){
try{
a()
}catch{
log
}
....
try{
a()
}catch{
log
}
}
こんなのやりだしたら関数戻り値チェックと変わらんしなあ
0058デフォルトの名無しさん
2010/03/06(土) 13:46:550059デフォルトの名無しさん
2010/03/06(土) 14:27:080060デフォルトの名無しさん
2010/03/06(土) 16:01:19その内容が重要であって細かい発生箇所なんて知ったこっちゃないわな。
目的が違うのだし、別途ログ管理クラスでも作ってログをとったほうがいいでしょ。
0061デフォルトの名無しさん
2010/03/06(土) 16:47:31まあそうだが、catchした頃にはそのthrow位置すら分からなくなってるんだよな
0062デフォルトの名無しさん
2010/03/06(土) 22:19:180063デフォルトの名無しさん
2010/03/07(日) 00:28:220064デフォルトの名無しさん
2010/03/07(日) 07:53:28throwの代わりに使えばいい
0065デフォルトの名無しさん
2010/03/07(日) 08:35:58パフォーマンス的に無理でしょ。
FUNC_INみたいなので関数は全て囲むってのはときどき見るけど、それでもコールスタックは
作れても呼び出し位置までは取れないんだよなあ。
0066デフォルトの名無しさん
2010/03/07(日) 09:30:040067デフォルトの名無しさん
2010/03/07(日) 13:16:310068デフォルトの名無しさん
2010/03/08(月) 02:13:130069デフォルトの名無しさん
2010/03/08(月) 03:22:28ユーザサイドで落ちた時は、原因追究の重要なフライトレコーダになるからねぇ。
0070デフォルトの名無しさん
2010/03/09(火) 07:07:490071デフォルトの名無しさん
2010/03/09(火) 07:26:31throw の場所と throw 時のコールスタックを取得する関数とか
0072デフォルトの名無しさん
2010/03/09(火) 10:02:43そんくらいサクッと作れ
0073デフォルトの名無しさん
2010/03/09(火) 10:50:510074デフォルトの名無しさん
2010/03/10(水) 01:37:530075デフォルトの名無しさん
2010/03/10(水) 05:16:200076デフォルトの名無しさん
2010/03/12(金) 08:11:190077デフォルトの名無しさん
2010/11/22(月) 07:21:200078デフォルトの名無しさん
2010/12/08(水) 12:19:20つかってたんだけど、C#では気軽に例外飛んでくる
から困る。
システムからオブジェクトは帰ってくるけど、使える
状態なのか例外でしか判断できないケースが一番
嫌だ。
0079デフォルトの名無しさん
2010/12/09(木) 10:59:34Windowsにも構造化例外があるだろ
って9ヶ月前のレスにレスしてるのか・・・
0080デフォルトの名無しさん
2011/04/28(木) 11:27:57.86> 561 返信:デフォルトの名無しさん[sage] 投稿日:2011/04/28(木) 03:25:09.83
> 次に、>>546のような深いネストがどうしても必要な場合
> 仮に例外で処理するなら error_handler() で catch するだろう
> そうすると途中の関数は例外処理がいらないから(デストラクタで処理できるリソースだけ使ってる場合は)簡単になるけど
> error_handler() を読むのが凄く難しくなる
> 深いネストを潜って source_of_error() まで到達する必要があるからね
> 581 名前:デフォルトの名無しさん[sage] 投稿日:2011/04/28(木) 11:22:24.06
> >>578
> error_handler() が全ての必要なエラーを補足できてるか知るためには
> 関数を遡って調べるしか無いでしょう?
> もし漏れてたらバグかもしれないし、または catch(...)で捕まえても
> 何のエラーか分からなきゃ碌な処理はできない
> 戻り値ならエラーのハンドリングはそれぞれの関数でやってるから
> 責任が局所化されてるわけ
0081天使 ◆uL5esZLBSE
2011/07/03(日) 20:14:31.45土方が何をいっても
0082デフォルトの名無しさん
2011/07/03(日) 20:58:09.220083デフォルトの名無しさん
2011/11/22(火) 12:55:08.85■ このスレッドは過去ログ倉庫に格納されています