effective C++などを読んでいると例外処理について多く触れられていますが、
そもそも例外処理はコードのバグなのであって対処するコード(try catch)がなぜあるのかがわかりません。
例外がでたらそこで直せばいいだけですし
例外ありきのコードは成立していないと思います。
例外処理について調べても上記についての説明がなされていないものでしたので
この例外処理を回避するコードがなぜ存在するのか教えていただきたい。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答11件
0
例外の意味を誤解しています。バグを拾う機構じゃないです。
関数やメソッドを呼び出した場合、
・成功と失敗を戻り値で返す
・戻れば成功で、失敗は例外発生で知らせる
という2通りの考え方があります。
例えばCでは前者の考え方なので、
C
1if((fp=fopen(fname,"r"))==NULL){ 2 perror("fopen 1"); 3 exit(1); 4}
のように呼び出す都度常にエラーチェックが必要です。
あるいは、「割り算する前に分母が0でないか確認してから割り算すべき」という考えに立てば、fopen
する前に別の関数でファイルの存在チェックやアクセス権チェックをしてからfopen
すべきかも知れません。
ディスクフル(やネットワークドライブのネット障害)を心配すると、fopen(fname,"w")
が成功してもその後のfprintf
やputc
が失敗するかも知れず、これら呼び出しの全てに返り値チェックが必要です。printf
でもリダイレクトされている可能性があるので同様。
十年くらい前(?)ですが、awk
でこのチェックが漏れていて、ディスクフルでも正常終了するというバグ情報を見ました。
こういう毎回の事前チェックや返り値チェックが煩わしいという考えに立って設計されたのが例外機構のある言語です。
本筋のロジックの流れが見やすいように書いて、本筋で無い処理は隅っこに書くという考え。
Cで実用的なプログラムが書けているわけで、すべて事前チェックもしくは返り値チェックを徹底すれば例外機構なしでも実用的なプログラムが書けます。ただ、それが読みやすいかどうかですね。
awk
のようなメジャーなツールですら徹底できていなかったという事実も受け止める必要があります。
投稿2020/07/29 15:14
総合スコア85901
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
プログラム動作意図から外れた状況に対処するという意味の「例外処理(エラーハンドリング)」と、プログラミング言語C++の機能として提供される 「例外機構(throw文とtry/catch構文)」 を区別して認識する必要があります。
C++に限らず、例外処理(エラーハンドリング)が必要になる状況は2つに分類できます:
- [A] プログラマのコード実装誤り: ヌルポインタ参照はがし、配列範囲外アクセス、未初期化変数からの読取りなど。
- [B] プログラム実行時の外部環境: ファイル不在、ネットワーク不達、ディスクFULLでファイル書き込めない、メモリ不足など。
例外がでたらそこで直せばいいだけですし
プログラマの責任範囲において直せるのは、[A] に対する例外処理(エラーハンドリング)のみです。
むしろプログラミング言語C++に限れば、[A] に対する例外機構はほとんど期待できません。例:ヌルポインタ参照はがしはC++例外機構を用いても検知できません。運が良ければ該当箇所でプログラム異常停止、運が悪いとランダムにデータ破損したり一見無関係な箇所でプログラム異常停止します。
他のプログラミング言語(例えばJavaやC#)ではヌルポインタ/参照はがしのようなロジックエラーでも、各言語における例外機構によって検知可能です(NullPointerException
や NullReferenceException
)。
例外ありきのコードは成立していないと思います。
実用的なプログラムであれば、[B] に対する例外処理(エラーハンドリング)を行うべきです。
プログラミング言語Cには例外機構が存在しないため、例外処理(エラーハンドリング)は「特殊な戻り値 や エラーコード」を用いて実現されます。
例:fopen
でファイルオープンに失敗すると関数は値NULL
を返し、エラー原因を表すコードをerrno
変数に格納する。
プログラミング言語C++の場合、ほとんどの標準ライブラリ機能は「例外機構」の存在を前提に設計・提供されます。サードパーティー製ライブラリでも、多くは標準ライブラリに準じた設計が行われます。
例:new MyClass()
でメモリ確保に失敗すると、std::bad_alloc
例外を送出する。
つまり実用的なC++プログラムを作るとなると、例外機構(throw文とtry/catch構文)を用いた例外処理(エラーハンドリング)を避けることはできません。
C++公式サイト(isocpp.org)のFAQ項目では下記ように説明されています。太字部は回答者による強調。括弧内は参考訳。
Why use exceptions?
(どうして例外を使うのか?)What good can using exceptions do for me? The basic answer is: Using exceptions for error handling makes your code simpler, cleaner, and less likely to miss errors.
(例外の利用にはどんな利点があるでしょう?基本的な回答は: エラーハンドリングに例外を使うことは、あなたのコードを単純、簡潔にし、そしてエラーが起きにくくなります。)
But what's wrong with "good old errno and if-statements"? The basic answer is: Using those, your error handling and your normal code are closely intertwined. That way, your code gets messy and it becomes hard to ensure that you have dealt with all errors (think "spaghetti code" or a "rat's nest of tests").
(では「古き良き error と if文」 の何が問題なのでしょう?基本的な回答は: それらを利用すると、エラーハンドリングと通常コードが密接に結び付いてしまいます。そこでは、あなたのコードはひどく散らかってしまい、あらゆるエラーの取り扱いを強制することを困難にします("スパゲッティコード" や "ネズミ捕り・テスト" を想像してください)。)First of all there are things that just can't be done right without exceptions. Consider an error detected in a constructor; how do you report the error? You throw an exception.
(まず第一に、例外なしには正しく処理できないケースが存在します。コンストラクタ中でのエラー検知を考えてください;どうやってエラーを報告しますか?例外を送出します。)
That's the basis of RAII (Resource Acquisition Is Initialization), which is the basis of some of the most effective modern C++ design techniques: A constructor's job is to establish the invariants for the class (create the environment in which the member functions are to run) and that often requires the acquisition of resources, such as memory, locks, files, sockets, etc.
(これはRAIIの基礎であり、とても有用なモダンC++設計テクニックの基礎となっています: コンストラクタの仕事はクラスの不変条件を確立する(メンバ関数を実行する環境を整える)ことであり、しばしばメモリ/ロック/ファイル/ソケットなどのリソース確保を要求します。)<以下略>
投稿2020/07/30 05:32
編集2020/07/30 06:09総合スコア6191
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/31 09:24
2020/07/31 14:50
2020/07/31 15:21
2020/08/04 08:52 編集
0
そもそも例外処理はコードのバグなのであって
この考え方が妥当ではありません。「通信が切断された」ような状況はプログラムにバグがなくても発生します。
投稿2020/07/29 10:29
総合スコア146018
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/29 13:41
2020/07/29 14:01 編集
2020/07/29 15:10
2020/07/29 20:30
2020/07/29 22:35
0
例外機構がない場合、返り値で処理の成功を判断することになります。確かにそういう考えの言語はあります、c言語とか。
そういう言語で例えば、
「処理A,B,C,Dを順番に行う、ただし各処理が失敗した時点で以降の処理は実行せず代わりにEを行う」
という処理を書こうとしたらif文が4つ並んでしまいます;
if(!A()){ E(); return; } if(!B()){ E(); return; } if(!C()){ E(); return; } if(!D()){ E(); return; }
他にも色々書き方はあるでしょうが、少なくとも「A,B,C,Dの順番で実行する」という本題からかなり余計なコードが増えることでしょう。
これが例外機構があればtry-catchですっきり書けます
try { A(); B(); C(); D(); } catch { E(); }
投稿2020/07/29 15:00
編集2020/07/30 04:26総合スコア13553
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
例外ありきのコードは成立していないと思います。
んなこたーない。
何らかの異常に対処できる(が検出はできない)関数が
何らかの異常を検出できる(が対処はできない)関数を 直接/間接的に呼んでいるとき、
その両者間で何らかの異常を伝達するスマートなやりかた が例外です。
※ バグで停止するんなら assert でもカマしておけばいいので。
投稿2020/07/29 10:34
編集2020/07/29 11:14総合スコア16612
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こんにちは。
そもそも例外処理はコードのバグなのであって対処するコード(try catch)がなぜあるのかがわかりません。
例外がでたらそこで直せばいいだけですし
例外ありきのコードは成立していないと思います。
2つの点で間違っていると思います。
まず、例外処理はバグ検出時にも良く使いますが、バグ以外のケースでも有用です。
次に、バグをなくすことは不可能ですのでバグ検出時の処理をしないのは危険過ぎます。めったに発生しない筈のバグ対処に例外機構を使うのは結構好ましい使い方と思います。
ところで、もしかしてバグのないプログラムが存在すると考えているのでしょうか?
↓がわかり易いです。短いので一読することをお勧めします。
バグのないソフトウェアの作れない理由
投稿2020/07/29 15:49
総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
例外など使わずに、関数やメソッドがエラーを戻り値で返して、それをチェックすればいいじゃないか、と考えていらっしゃるかもしれません。しかし、それがきれいに出来ない状況がたくさんあるのです。
例えば、コンストラクタは戻り値を返すようにはできていません。コンストラクタは、テンポラリ・オブジェクトの生成や引数を渡すときなど、戻り値がチェックできないような場所でも頻繁に使われるからです。オーバーロードした演算子も同様です。しかし、コンストラクタや演算子でもエラーは発生することがあります。そのエラーをクラスの利用者に通知する必要があります。
また、vectorなどのコンテナは、その中身がどんなエラーを返すか事前に知ることはできません。vectorがサイズを変更しているときに、中身で起きたエラーを、vectorのコードを飛び越して利用者に通知するメカニズムが必要です。
例外は、エラーを抽象化して正常処理から分離することにより、正常処理のコードをわかりやすく、しかも再利用可能な形で書けるようにしているのです。例外がなければ、C++の抽象化をする能力は中途半端なものになり、「だったらCで十分だよね」ということになっていたと思います。
投稿2020/07/29 13:59
総合スコア430
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
「例外がでたらそこで直せばいい」のとは違います。通信の応答が規定時間内になかったなどは回線の状態によっては頻発することが有ります。・・・1μ短縮出来たら受けられた・・・かも知れない・・・で1μ短縮したがダメだったw・・・などなど、きりがありません。
“人間は、間違いを犯すもの”です。・・・そして、通常運用されるプログラムは、少なくとも数万行とかのレベルです。“そこ”を治すたには、他に影響が出ないか細心の注意が必要です。そのために、想定される問題を先取り(考慮)して、例外処理を入れるのです。
逆に『考慮ミスは。立派なバグです』
投稿2020/07/29 10:57
総合スコア6851
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/29 13:45
2020/07/29 14:58 編集
0
ちょっと何言ってるかわかりません.
一体何をもって「コードのバグ」だと言っているのか?
例外という機構があります.throwとtryとcatchという仕組みが.
→それを何に使うかはプログラマ次第です.
投稿2020/07/29 10:23
総合スコア11996
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/30 01:43
2020/07/30 01:53
0
例外が必要か? という話であれば絶対に必要というわけではありません
いろいろな言語が存在していますが、
「こんな機能があった方が書きやすいのでは」
「こういう仕様の方が安全なのでは」
と、それぞれの考え方によって設計されています
その中で
例外みたいな機能あった方がいいよね、と考えた人達が居たわけです
例)自分でメモリ開放するよりGCに任せた方が安全だよね
さてその例外についてですが
他の方も回答されているように例外発生=バグではありません
例えば指定されたファイルを読み込んで、その中の値を使って何か処理をする
というプログラムを考えたとき
正常にファイルが読み込めない可能性があります
HDDが故障しているかもしれないですし誰かが外付けHDDのコードに脚を引っ掛けるかもしれないです
こういったドライブ側の都合でファイルが読めないのは「プログラム上のバグ」とは言えないですよね
しかしいずれにしてもファイルは正常に読めなかったのだから以降の処理は行なえません
この「ファイルは正常に読めなかった」問題に対応するのはプログラム側の仕事です
ここでファイルを開く関数が結果コード(開けたら1、開けなかったら0とか)を返してそれをifで判定しするという言語仕様でも可能ですが、
開けなかったら問題の情報を詰めた例外投げてcatchまですっ飛ばしてしまおう、という思想の言語もあるということです。
仮に
「開くファイルが3つあってそのどれか1つでも開けなかったら以降の処理はできない、ファイルが開けなかったことはコンソールに出力してね」
だったらどうでしょうか
3つそれぞれにifを噛ませるより、どのファイルからでも同じcatch節に飛ばす方が処理がスッキリして見えないでしょうか
投稿2020/07/30 03:19
総合スコア610
0
バグではありません。仕様です。
違った。
例外が発生することを仕様に盛り込むことで、柔軟に対応できる様になります。
ユーザーが使うアプリが例外メッセージをそのまま出すのはバグと言ってもいいでしょう。
ユーザーが使うアプリを作る人には、例外として通知します。そうすることで、エラーとして終わる様な処理をすることと、なんらかの対策をしてリカバリーできることを選ぶことができます。
もちろん、戻り値として通知することもできますが、例外として通知すると、呼び出しの深い階層から一気に戻ることや、エラー処理を1箇所にまとめて記述することができる様になります。
投稿2020/07/29 10:14
総合スコア995
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/07/29 13:37
2020/07/29 13:58 編集
2020/08/01 05:23
2020/08/01 10:46
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。