2ちゃんねる ★スマホ版★ ■掲示板に戻る■ 全部 1- 最新50  

■ このスレッドは過去ログ倉庫に格納されています

例外機構を考察するスレ

1 :デフォルトの名無しさん:2009/08/10(月) 10:57:51

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

2 :デフォルトの名無しさん:2009/08/10(月) 11:00:29
このスレッドは天才チンパンジー「アイちゃん」が
言語訓練のために立てたものです。

アイと研究員とのやり取りに利用するスレッドなので、
関係者以外は書きこまないで下さい。

                  京都大学霊長類研究所

3 :デフォルトの名無しさん:2009/08/10(月) 11:13:08
基本は、C++の
try { } catch(...) { } finally { }
だよな。SEHでは:
__try { } __except(...) { }
__try { } __finally { }
となる。

4 :デフォルトの名無しさん:2009/08/10(月) 11:16:44
BASICでは、昔、on error goto文しか使えなかったが、VB.NETでは
Try/Catchブロックが使えるようになった。

5 :デフォルトの名無しさん:2009/08/10(月) 11:18:53
混同しやすいが、C++の(標準の)例外と、SEHは別物である
ということに注意。

6 :デフォルトの名無しさん:2009/08/10(月) 11:20:48
SEHの__tryなどは、互換性などの問題のため、大文字のマクロに
変えることがある。
__TRY { } __EXCEPT(...) { }
__TRY { } __FINALLY { }

7 :デフォルトの名無しさん:2009/08/10(月) 11:47:37
何か質問は?

8 :デフォルトの名無しさん:2009/08/10(月) 12:37:38
例外安全とは何ぞや?

9 :デフォルトの名無しさん:2009/08/10(月) 13:14:24
例外安全なプログラミングとは、例外を投げる可能性があるコードが
実際に例外を投げた場合に、プログラムの状態が壊れずリソースも
リークしないように作るプログラミングのことを言います。

http://www.kmonos.net/alang/d/2.0/exception-safe.html

10 :デフォルトの名無しさん:2009/08/10(月) 13:16:48
何かの処理の途中で例外が発生しても、
オブジェクトが更新途中の中途半端で不完全な内部状態のままになったりせず、
呼び出し前の正常な内部状態に戻る性質

11 :デフォルトの名無しさん:2009/08/10(月) 16:05:52
例外処理の中で例外が起きた場合の対応ってみんなしてるのだろうか?

12 :デフォルトの名無しさん:2009/08/10(月) 17:06:54
そもそも、例外が起きるような処理はしない。

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

13 :デフォルトの名無しさん:2009/08/10(月) 18:27:32
今は標準C++でもfinallyあるの?

14 :デフォルトの名無しさん:2009/08/10(月) 19:08:49
C++ってtryブロックの中に書いたコードは
外に書いたコードより低速でメモリ使用も膨れるの?

15 :デフォルトの名無しさん:2009/08/10(月) 19:39:20
処理系の実装方法による。

16 :デフォルトの名無しさん:2009/08/10(月) 19:40:43
一般的には入口と出口でコストがかかるだけ
かからない実装もある
中が外より遅いとかってことはないはず

17 :デフォルトの名無しさん:2009/08/10(月) 19:59:55
int 3

18 :デフォルトの名無しさん:2009/08/11(火) 07:22:47
>> 3
C++にfinallyはないよ

19 :デフォルトの名無しさん:2009/08/11(火) 07:38:50
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 :デフォルトの名無しさん:2009/08/11(火) 08:09:19
Common Lispのconditionが一番使いやすい

21 :デフォルトの名無しさん:2009/08/11(火) 11:18:13
>>19
GC 完備の言語だと destructor でリソース廃棄ってのをしにくいから
finally がいるかもしらんが、C++ だと普通スコープを抜ければ
finally がなくても自動的に dtor で話が済むと思うのだが...

22 :デフォルトの名無しさん:2009/08/11(火) 13:08:35
>>21
> GC 完備の言語だと destructor でリソース廃棄ってのをしにくいから
GCありでRAIIってまずいの?

もしリソース解法タイミングの遅延を問題にしているのなら、
C#でもIDispopsable + usingで解決するけど…他にもなにかあるのだろうか?

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

24 :デフォルトの名無しさん:2009/08/11(火) 14:22:19
>>22
遅延したデストラクタ内で発生した例外は誰が受け取るの?

25 :デフォルトの名無しさん:2009/08/11(火) 14:27:28
デストラクタで例外を投げんな

26 :デフォルトの名無しさん:2009/08/11(火) 14:44:09
>>25
RAII使ってたらその必要に迫られることがある。

27 :デフォルトの名無しさん:2009/08/11(火) 14:58:44
迫られないよ。
RAIIは解放を全自動化できる魔法の弾丸じゃないのだから、
処理用の関数を用意しておいてそれを呼んで資源解放すれば良い。

なぜこうするのか。
デストラクタから例外が投げられた場合、
C++ならterminateされる場合もあるし未定義の動作の原因となる。
C++以外でも破壊が中途半端に終わり壊れたオブジェクトになる。
あと、Disposeから例外を投げた場合も同様に壊れたオブジェクトになるよ。

28 :デフォルトの名無しさん:2009/08/11(火) 21:01:16
>>27
RAIIを使って、資源の確保はオートマチックな感じにやるけど
解放は手動でやれ、ってこと?

29 :デフォルトの名無しさん:2009/08/11(火) 21:38:13
RAIIに限らず、デストラクタで例外を発生させるのはご法度。
例外が発生するような解放処理なら、手動でやらなきゃならない。

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

30 :デフォルトの名無しさん:2009/08/11(火) 22:26:51
デストラクタでの例外発生が御法度なのは
まともな本ならちゃんと書いてある
どうしても例外起こる可能性のある処理をするなら
例外を握りつぶしてからエラーログを吐くなりなんなりする

31 :デフォルトの名無しさん:2009/08/12(水) 00:49:44
>>23
badallocになった時って、例外用のインスタンスって生成できる?


32 :デフォルトの名無しさん:2009/08/12(水) 01:36:37
>>23じゃないが、メモリ不足などでbadallocになったら、
メモリ確保なしでできることしかできない=何もできない。
システムがプログラムを落としてくれることを願う以上は実質何もできない。

33 :デフォルトの名無しさん:2009/08/12(水) 02:15:03
23だけど例外クラスのなかでヒープをつかわなければいいんじゃないの?それか予め確保して置いたメモリを開放して作業領域を作るとか


34 :デフォルトの名無しさん:2009/08/12(水) 10:15:19
処理系によるね
bad_alloc 用のメモリを残してくれている可能性もあるし、そうでない可能性もある
昔 GCC でやったら、小さいメモリの確保に失敗した時はプログラムが強制終了されたな
terminate だったのかそうでないのかは忘れたが

どちらにしろ、ギリギリ bad_alloc できたとしても、
catch 内で出来る事はすくないんだけどね・・・

35 :デフォルトの名無しさん:2009/08/12(水) 12:42:28
>>34
それはgccというかLinuxでの挙動じゃないか?
SIGKILを送りつけられてしまうから、問答無用、terminateなしで殺される

36 :デフォルトの名無しさん:2009/08/12(水) 12:47:29
>>34
それを回避するには、楽観的メモリ確保戦略を禁止しないといけない。

37 :デフォルトの名無しさん:2009/08/12(水) 20:36:46
OOM Killerで殺されるのは、malloc時じゃなくて、使ったときだから
>>34 とは違う

38 :デフォルトの名無しさん:2009/10/17(土) 01:30:58
ハリウッドの原則な設計(基底クラスが派生クラスの関数を呼ぶ) + 例外ってどうしてます?
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 :デフォルトの名無しさん:2009/10/17(土) 02:59:38
JavaのRuntimeExceptionとErrorは、throwsの宣言が不要。
要するに、投げてよい例外を規定しなければならないタイプの例外と、
規定しなくてよい (規定するのが難しい) 例外があるってこと。

40 :デフォルトの名無しさん:2009/10/17(土) 04:35:22
>>38
例外の前にコンパイルエラーになるから安心しろ。

41 :デフォルトの名無しさん:2009/10/17(土) 04:47:21
>>38
設計時の問題だと思うんだけど。
子クラスが親クラスの知らない例外を投げること自体は必要だという前提でいいんだよね?
なら、それをどこでハンドリングするかというのも考慮してあるはずじゃないかな。


あと、
>  ・Child::doInnerから例外を投げないように注意して作ってもらう or 投げてよい例外を規定する
のときの
>     →派生クラス側で間違えたらNG。
はアサーションでいいでしょ。

破綻するなら、ハリウッドの原則な設計を採用したことが間違いだったんだよ。

42 :デフォルトの名無しさん:2009/10/17(土) 09:22:04
ハリウッド?

43 :デフォルトの名無しさん:2009/10/18(日) 03:39:58
ありがとうございます。

>>39,40
Javaならそれでいい(必要なものを宣言すればいい)のですが、C#は例外仕様を書くことすらできず、
C++は例外仕様を書いてもコンパイラではチェックせず動作中に違反すると即落ちてしまいます。
# C++の奴は、実質"OffにできないAssert"という地雷で"使用するな"としている書籍も多数

>>41
> 子クラスが親クラスの知らない例外を投げること自体は必要だという前提でいいんだよね?
> なら、それをどこでハンドリングするかというのも考慮してあるはずじゃないかな。
前提はそうです。が、親子だけで例外をどっちで掴むかしか考えていませんでした。
全体でハンドリングを考えてみると、
「子に親の知らない例外を投げさせる事自体禁止する」か、
「(親の利用者が子も知っている前提なら)利用者が子の投げた例外を掴む」か、
「子が投げる例外は、誰も掴まない」か、ぐらいから選ぶしかなさそうですね。
ちょっと全体設計を見直してみます。

> はアサーションでいいでしょ。
それが一番簡単で確実そうですね。

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

45 :デフォルトの名無しさん:2009/10/18(日) 16:20:38
>>42
ttp://en.wikipedia.org/wiki/Hollywood_Principle

46 :デフォルトの名無しさん:2009/10/23(金) 12:45:15
http://d.hatena.ne.jp/xna/20091018/1255876308

ネイティブアーキテクチャを変える時ってほんと好き放題やれるよな

47 :デフォルトの名無しさん:2009/11/28(土) 15:47:57
頻繁にtryブロックに入ったり出たりするコードは
アホって事?

48 :デフォルトの名無しさん:2009/11/28(土) 23:13:47
言語とコンパイラによる

49 :デフォルトの名無しさん:2009/11/29(日) 00:46:59
理由による。
tryの用法には「非標準的な実行エラー(想定した状況から逸脱した状況)をどこかで集中的に対処」と
「finallyでリソース解法」の二種類があり、それらは書式が同じだけで中身は全くの別物。

前者が大量にあるのなら使い方/設計が正しいかを疑うべき。
例外処理を集約できていなかったり、処理できないのにcatchしてたり、例外にすべきでないものを例外にしている可能性がある。
後者が大量にあるのならそれ自体は例外処理としては問題ではない。
ただ、別な問題としてリソース解法漏れにならぬようRAII型導入を考えたほうがベター。

かく言う俺も会社の方針で「Assert禁止。代わりに例外投げろ」なんて
やっているから実行エラーもバグも混在してヒドいことになっているがw

50 :デフォルトの名無しさん:2009/11/29(日) 00:55:14
>>49
そうじゃなくて、tryを書くことで実行時のオーバーヘッドが大きいかどうか
という話かと。

51 :デフォルトの名無しさん:2009/11/29(日) 01:10:54
>>50
そうなの?
不要なtryをやたらと書く、例えば「あちこちに大量にtryを書いてログを取る」とか、そのレベルの話かとオモタ

52 :デフォルトの名無しさん:2009/12/03(木) 13:42:16
>>50
それは処理系によるとか言えんよな
gccでも例外発生時は遅いけど実行時のオーバーヘッドは0のと、例外発生時も早いけど一定のオーバーヘッドがある2系統選べるし

53 :デフォルトの名無しさん:2010/03/05(金) 08:36:26
例外って細かなロギングが難しくなるよね

54 :デフォルトの名無しさん:2010/03/05(金) 22:41:19
細かく例外クラスを作ればいいじゃない

55 :デフォルトの名無しさん:2010/03/06(土) 01:56:38
いやthrow時だけじゃなくコールスタックとか関数コール位置とかを正確に取るのが。できなくないけど煩雑になる。
特にC++だとやっかい。

56 :デフォルトの名無しさん:2010/03/06(土) 12:08:08
つうかC++以外はたいていスタックトレース取得できるんじゃね

57 :デフォルトの名無しさん:2010/03/06(土) 13:13:26
スタックトレースというかコール行数も取りたいんだよね。
f(){
a();
....
a();
}
どちらのaを呼んだかとかをさ
f(){
try{
a()
}catch{
log
}
....

try{
a()
}catch{
log
}
}

こんなのやりだしたら関数戻り値チェックと変わらんしなあ



58 :デフォルトの名無しさん:2010/03/06(土) 13:46:55
throw new Exception(__FILE__, __LINE__);

59 :デフォルトの名無しさん:2010/03/06(土) 14:27:08
いやそれだとthrow位置が取れるだけだから

60 :デフォルトの名無しさん:2010/03/06(土) 16:01:19
そもそも例外機構は例外を集中的にハンドリングすることが目的だから
その内容が重要であって細かい発生箇所なんて知ったこっちゃないわな。
目的が違うのだし、別途ログ管理クラスでも作ってログをとったほうがいいでしょ。

61 :デフォルトの名無しさん:2010/03/06(土) 16:47:31
>>59
まあそうだが、catchした頃にはそのthrow位置すら分からなくなってるんだよな

62 :デフォルトの名無しさん:2010/03/06(土) 22:19:18
throw位置が取れれば少なくともデバッグには十分だと思うが

63 :デフォルトの名無しさん:2010/03/07(日) 00:28:22
より多くの情報が取れるに越したことはないかなと

64 :デフォルトの名無しさん:2010/03/07(日) 07:53:28
呼び出し位置でのコールスタックをグローバルに保存してからthrowするヘルパ関数を
throwの代わりに使えばいい

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

66 :デフォルトの名無しさん:2010/03/07(日) 09:30:04
throwの代わりに自作のthrow_ex使うって話だからオーバーヘッドは無いだろ。

67 :デフォルトの名無しさん:2010/03/07(日) 13:16:31
いや呼び出し位置でなんかするってのは無理ってこと

68 :デフォルトの名無しさん:2010/03/08(月) 02:13:13
デバッガでブレーク張れば済むんじゃないの?

69 :デフォルトの名無しさん:2010/03/08(月) 03:22:28
そもそもログいらなくね?ってのを言いだしちゃうとまあ・・
ユーザサイドで落ちた時は、原因追究の重要なフライトレコーダになるからねぇ。

70 :デフォルトの名無しさん:2010/03/09(火) 07:07:49
ダ・ン・プ!ダ・ン・プ!

71 :デフォルトの名無しさん:2010/03/09(火) 07:26:31
開発環境自体に throw 時の情報を提供できる機能がついてればいいんだけどね
throw の場所と throw 時のコールスタックを取得する関数とか

72 :デフォルトの名無しさん:2010/03/09(火) 10:02:43
開発環境に頼る必要ないだろw
そんくらいサクッと作れ

73 :デフォルトの名無しさん:2010/03/09(火) 10:50:51
で、それがサクッと作れないよねって話をだな・・

74 :デフォルトの名無しさん:2010/03/10(水) 01:37:53
windowsはしらんけどlinuxならさくっと作れるぞ

75 :デフォルトの名無しさん:2010/03/10(水) 05:16:20
そうなんだっけ?

76 :デフォルトの名無しさん:2010/03/12(金) 08:11:19
まあ楽できる分細かいことはできなくなるということだ

18 KB
■ このスレッドは過去ログ倉庫に格納されています

★スマホ版★ 掲示板に戻る 全部 前100 次100 最新50

read.cgi ver 05.02.02 2014/06/23 Mango Mangüé ★
FOX ★ DSO(Dynamic Shared Object)