2011年10月1期プログラム例外機構を考察するスレ TOP カテ一覧 スレ一覧 削除依頼
・ 次のスレ
【緊急アンケート】ム板でiPhone使ってる奴の数→
攻守最強のプログラミング言語は?
コンピュータ基本知識
プログラムとか全然知らない初心者だけど


例外機構を考察するスレ


1 :09/08/10 〜 最終レス :11/11/22

例外さんについて語ってください。
(言語は問わない)

2 :
このスレッドは天才pンジー「アイちゃん」が
言語訓練のために立てたものです。
アイと研究員とのやり取りに利用するスレッドなので、
関係者以外は書きこまないで下さい。
                  京都大学霊長類研究所

3 :
基本は、C++の
try { } catch(...) { } finally { }
だよな。SEHでは:
__try { } __except(...) { }
__try { } __finally { }
となる。

4 :
BASICでは、昔、on error goto文しか使えなかったが、VB.NETでは
Try/Catchブロックが使えるようになった。

5 :
混同しやすいが、C++の(標準の)例外と、SEHは別物である
ということに注意。

6 :
SEHの__tryなどは、互換性などの問題のため、大文字のマクロに
変えることがある。
__TRY { } __EXCEPT(...) { }
__TRY { } __FINALLY { }

7 :
何か質問は?

8 :
例外安全とは何ぞや?

9 :
例外安全なプログラミングとは、例外を投げる可能性があるコードが
実際に例外を投げた場合に、プログラムの状態が壊れずリソースも
リークしないように作るプログラミングのことを言います。
http://www.kmonos.net/alang/d/2.0/exception-safe.html

10 :
何かの処理の途中で例外が発生しても、
オブジェクトが更新途中の中途半端で不完全な内部状態のままになったりせず、
呼び出し前の正常な内部状態に戻る性質

11 :
例外処理の中で例外が起きた場合の対応ってみんなしてるのだろうか?

12 :
そもそも、例外が起きるような処理はしない。
どうしてもやらなきゃならない場合は
例外を握りつぶしても例外安全になるように作る。
ミスが入りやすいし手間がかかるから、極力やらないど。

13 :
今は標準C++でもfinallyあるの?

14 :
C++ってtryブロックの中に書いたコードは
外に書いたコードより低速でメモリ使用も膨れるの?

15 :
処理系の実装方法による。

16 :
一般的には入口と出口でコストがかかるだけ
かからない実装もある
中が外より遅いとかってことはないはず

17 :
int 3

18 :
>> 3
C++にfinallyはないよ

19 :
C#の中の人の発言
http://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

20 :
Common Lispのconditionが一番使いやすい

21 :
>>19
GC 完備の言語だと destructor でリソース廃棄ってのをしにくいから
finally がいるかもしらんが、C++ だと普通スコープを抜ければ
finally がなくても自動的に dtor で話が済むと思うのだが...

22 :
>>21
> GC 完備の言語だと destructor でリソース廃棄ってのをしにくいから
GCありでRAIIってまずいの?
もしリソース解法タイミングの遅延を問題にしているのなら、
C#でもIDispopsable + usingで解決するけど…他にもなにかあるのだろうか?

23 :
C++であるクラスがなげる例外を明確にする&依存関係解消のために
インターフェース内のネストクラスとして例外クラスを提供して
それ以外の例外は絶対に投げない
(標準の例外もBadAllocといった感じでラップする)
といった感じでやってるんだが
もっといいやり方はないんだろうか

24 :
>>22
遅延したデストラクタ内で発生した例外は誰が受け取るの?

25 :
デストラクタで例外を投げんな

26 :
>>25
RAII使ってたらその必要に迫られることがある。

27 :
迫られないよ。
RAIIは解放を全自動化できる魔法の弾丸じゃないのだから、
処理用の関数を用意しておいてそれを呼んで資源解放すれば良い。
なぜこうするのか。
デストラクタから例外が投げられた場合、
C++ならterminateされる場合もあるし未定義の動作の原因となる。
C++以外でも破壊が中途半端に終わり壊れたオブジェクトになる。
あと、Disposeから例外を投げた場合も同様に壊れたオブジェクトになるよ。

28 :
>>27
RAIIを使って、資源の確保はオートマチックな感じにやるけど
解放は手動でやれ、ってこと?

29 :
RAIIに限らず、デストラクタで例外を発生させるのはご法度。
例外が発生するような解放処理なら、手動でやらなきゃならない。
例えば、例外が発生してローカル変数のデストラクタが呼ばれ
ローカル変数のデストラクタで例外を発生させたら、C++なら即死する。
たとえ即死しなくても、デストラクタ中から例外を投げたら
その後の処理が(多くの場合、その親クラスのデストラクタすら)実行されず危険。
デストラクタでは例外が発生してもその場で即時握りつぶす以上はできない。

30 :
デストラクタでの例外発生が御法度なのは
まともな本ならちゃんと書いてある
どうしても例外起こる可能性のある処理をするなら
例外を握りつぶしてからエラーログを吐くなりなんなりする

31 :
>>23
badallocになった時って、例外用のインスタンスって生成できる?

32 :
>>23じゃないが、メモリ不足などでbadallocになったら、
メモリ確保なしでできることしかできない=何もできない。
システムがプログラムを落としてくれることを願う以上は実質何もできない。

33 :
23だけど例外クラスのなかでヒープをつかわなければいいんじゃないの?それか予め確保して置いたメモリを開放して作業領域を作るとか

34 :
処理系によるね
bad_alloc 用のメモリを残してくれている可能性もあるし、そうでない可能性もある
昔 GCC でやったら、小さいメモリの確保に失敗した時はプログラムが強制終了されたな
terminate だったのかそうでないのかは忘れたが
どちらにしろ、ギリギリ bad_alloc できたとしても、
catch 内で出来る事はすくないんだけどね・・・

35 :
>>34
それはgccというかLinuxでの挙動じゃないか?
SIGKILを送りつけられてしまうから、問答無用、terminateなしでされる

36 :
>>34
それを回避するには、楽観的メモリ確保戦略を禁止しないといけない。

37 :
OOM Killerでされるのは、malloc時じゃなくて、使ったときだから
>>34 とは違う

38 :
ハリウッドの原則な設計(基底クラスが派生クラスの関数を呼ぶ) + 例外ってどうしてます?
class 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。
と、どこかで破綻する気が。

39 :
JavaのRuntimeExceptionとErrorは、throwsの宣言が不要。
要するに、投げてよい例外を規定しなければならないタイプの例外と、
規定しなくてよい (規定するのが難しい) 例外があるってこと。

40 :
>>38
例外の前にコンパイルエラーになるから安心しろ。

41 :
>>38
設計時の問題だと思うんだけど。
子クラスが親クラスの知らない例外を投げること自体は必要だという前提でいいんだよね?
なら、それをどこでハンドリングするかというのも考慮してあるはずじゃないかな。
あと、
>  ・Child::doInnerから例外を投げないように注意して作ってもらう or 投げてよい例外を規定する
のときの
>     →派生クラス側で間違えたらNG。
はアサーションでいいでしょ。
破綻するなら、ハリウッドの原則な設計を採用したことが間違いだったんだよ。

42 :
ハリウッド?

43 :
ありがとうございます。
>>39,40
Javaならそれでいい(必要なものを宣言すればいい)のですが、C#は例外仕様を書くことすらできず、
C++は例外仕様を書いてもコンパイラではチェックせず動作中に違反すると即落ちてしまいます。
# C++の奴は、実質"OffにできないAssert"という地雷で"使用するな"としている書籍も多数
>>41
> 子クラスが親クラスの知らない例外を投げること自体は必要だという前提でいいんだよね?
> なら、それをどこでハンドリングするかというのも考慮してあるはずじゃないかな。
前提はそうです。が、親子だけで例外をどっちで掴むかしか考えていませんでした。
全体でハンドリングを考えてみると、
「子に親の知らない例外を投げさせる事自体禁止する」か、
「(親の利用者が子も知っている前提なら)利用者が子の投げた例外を掴む」か、
「子が投げる例外は、誰も掴まない」か、ぐらいから選ぶしかなさそうですね。
ちょっと全体設計を見直してみます。
> はアサーションでいいでしょ。
それが一番簡単で確実そうですね。

44 :
>>43
俺が言いたかったのは do は予約語だからメソッド名に使ったらコンパイルエラーになるってこと。

45 :
>>42
ttp://en.wikipedia.org/wiki/Hollywood_Principle

46 :
http://d.hatena.ne.jp/xna/20091018/1255876308
ネイティブアーキテクチャを変える時ってほんと好き放題やれるよな

47 :
頻繁にtryブロックに入ったり出たりするコードは
アホって事?

48 :
言語とコンパイラによる

49 :
理由による。
tryの用法には「非標準的な実行エラー(想定した状況から逸脱した状況)をどこかで集中的に対処」と
「finallyでリソース解法」の二種類があり、それらは書式が同じだけで中身は全くの別物。
前者が大量にあるのなら使い方/設計が正しいかを疑うべき。
例外処理を集約できていなかったり、処理できないのにcatchしてたり、例外にすべきでないものを例外にしている可能性がある。
後者が大量にあるのならそれ自体は例外処理としては問題ではない。
ただ、別な問題としてリソース解法漏れにならぬようRAII型導入を考えたほうがベター。
かく言う俺も会社の方針で「Assert禁止。代わりに例外投げろ」なんて
やっているから実行エラーもバグも混在してヒドいことになっているがw

50 :
>>49
そうじゃなくて、tryを書くことで実行時のオーバーヘッドが大きいかどうか
という話かと。

51 :
>>50
そうなの?
不要なtryをやたらと書く、例えば「あちこちに大量にtryを書いてログを取る」とか、そのレベルの話かとオモタ

52 :
>>50
それは処理系によるとか言えんよな
gccでも例外発生時は遅いけど実行時のオーバーヘッドは0のと、例外発生時も早いけど一定のオーバーヘッドがある2系統選べるし

53 :
例外って細かなロギングが難しくなるよね

54 :
細かく例外クラスを作ればいいじゃない

55 :
いやthrow時だけじゃなくコールスタックとか関数コール位置とかを正確に取るのが。できなくないけど煩雑になる。
特にC++だとやっかい。

56 :
つうかC++以外はたいていスタックトレース取得できるんじゃね

57 :
スタックトレースというかコール行数も取りたいんだよね。
f(){
a();
....
a();
}
どちらのaを呼んだかとかをさ
f(){
try{
a()
}catch{
log
}
....
try{
a()
}catch{
log
}
}
こんなのやりだしたら関数戻り値チェックと変わらんしなあ

58 :
throw new Exception(__FILE__, __LINE__);

59 :
いやそれだとthrow位置が取れるだけだから

60 :
そもそも例外機構は例外を集中的にハンドリングすることが目的だから
その内容が重要であって細かい発生箇所なんて知ったこっちゃないわな。
目的が違うのだし、別途ログ管理クラスでも作ってログをとったほうがいいでしょ。

61 :
>>59
まあそうだが、catchした頃にはそのthrow位置すら分からなくなってるんだよな

62 :
throw位置が取れれば少なくともデバッグには十分だと思うが

63 :
より多くの情報が取れるに越したことはないかなと

64 :
呼び出し位置でのコールスタックをグローバルに保存してからthrowするヘルパ関数を
throwの代わりに使えばいい

65 :
いやいやコールする時にはthrowされるかわからないからスタックに入れるとかは
パフォーマンス的に無理でしょ。
FUNC_INみたいなので関数は全て囲むってのはときどき見るけど、それでもコールスタックは
作れても呼び出し位置までは取れないんだよなあ。

66 :
throwの代わりに自作のthrow_ex使うって話だからオーバーヘッドは無いだろ。

67 :
いや呼び出し位置でなんかするってのは無理ってこと

68 :
デバッガでブレーク張れば済むんじゃないの?

69 :
そもそもログいらなくね?ってのを言いだしちゃうとまあ・・
ユーザサイドで落ちた時は、原因追究の重要なフライトレコーダになるからねぇ。

70 :
ダ・ン・プ!ダ・ン・プ!

71 :
開発環境自体に throw 時の情報を提供できる機能がついてればいいんだけどね
throw の場所と throw 時のコールスタックを取得する関数とか

72 :
開発環境に頼る必要ないだろw
そんくらいサクッと作れ

73 :
で、それがサクッと作れないよねって話をだな・・

74 :
windowsはしらんけどlinuxならさくっと作れるぞ

75 :
そうなんだっけ?

76 :
まあ楽できる分細かいことはできなくなるということだ

77 :
http://hibari.2ch.net/test/read.cgi/prog/1289342444/

78 :
C++やってるときは例外は最終手段的な位置づけで
つかってたんだけど、C#では気軽に例外飛んでくる
から困る。
システムからオブジェクトは帰ってくるけど、使える
状態なのか例外でしか判断できないケースが一番
嫌だ。

79 :
>>74
Windowsにも構造化例外があるだろ
って9ヶ月前のレスにレスしてるのか・・・

80 :
http://hibari.2ch.net/test/read.cgi/tech/1302588918/546-579
> 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(...)で捕まえても
> 何のエラーか分からなきゃ碌な処理はできない
> 戻り値ならエラーのハンドリングはそれぞれの関数でやってるから
> 責任が局所化されてるわけ

81 :
でもお前はゴミなのにねww
土方が何をいっても

82 :
天使ちゃんマジ天使

83 :11/11/22
。。。
TOP カテ一覧 スレ一覧 削除依頼
・ 次のスレ
【緊急アンケート】ム板でiPhone使ってる奴の数→
攻守最強のプログラミング言語は?
コンピュータ基本知識
プログラムとか全然知らない初心者だけど