英語版
このページの英語版を見る

エラー

来て、コーディングして、クラッシュした。 ジュリアス・セステール

Erroneous D-Man
すべてのプログラムはエラーに対処しなければならない。エラーとは予期せぬ事態のことである。 を指す。一般的なエラーの例としては、次のようなものがある。 である:

エラー処理の問題

伝統的なC言語によるエラーの検出と報告方法は、伝統的なものではない、 アドホックなものであり、関数によって異なる:

このようなエラーに対処するためには、面倒なエラー処理コードを各関数呼び出しに追加しなければならない。 を追加しなければならない。エラーが起きたら、エラーから回復するコードを書かなければならない。 エラーから回復するためのコードを書かなければならない。 エラーをユーザーに報告しなければならない。ローカルで処理できないエラーは、明示的に呼び出し元に伝えなければならない。 呼び出し元に伝えられる必要がある。 errno値の長いリストは、適切なテキストに変換して表示する必要がある。 テキストに変換する必要がある。これを行うためのコードをすべて追加することは、プロジェクトのコーディングに費やす時間の大部分を費やすことになる。 さらに、新しいerrno値がランタイム・システムに追加された場合、古いerrno値はerrno値から削除される。 新しいerrno値がランタイム・システムに追加された場合、古いコードは意味のあるエラー・メッセージを適切に表示することができない。 エラーメッセージを適切に表示することができない。

優れたエラー処理コードは、そうでなければすっきりとした実装になるはずのものを、乱雑にしてしまいがちだ。 を乱雑にしてしまう。

さらに悪いことに、優れたエラー処理コードはそれ自体がエラーを起こしやすく、プロジェクトの中で最もテストされていない(したがってバグが多い)部分になりがちである。 プロジェクトの中で最もテストされていない(したがってバグが多い)部分になりがちである。 単に省略される。最終的な結果は、プログラムが予期せぬエラーに対処できず、「死のブルースクリーン」となる可能性が高い。 プログラムが予期せぬエラーに対処できなかったからである。

クイック&ダーティなプログラムには、面倒なエラー処理コードを書く価値はない。 このようなユーティリティは、刃のガードもないテーブルソーを使うようなものだ。 を使うようなものだ。

必要なのは、次のようなエラー処理の哲学と方法論である:

Dエラー処理ソリューション

まず、エラーについていくつかの観察と仮定をしてみよう:

解決策は、例外処理を使用してエラーを報告することである。すべての エラーはすべて、抽象クラス Error.Error を生成するtoString()という純粋な仮想関数がある。string を生成する。

コードが"out of memory"のようなエラーを検出すると、"Out of memory"というメッセージとともにError 。 がスローされる。関数呼び出しスタックが巻き戻される、 ハンドラを探す。 最後にブロック が実行される。 ブロックが実行される。エラーハンドラが見つかれば、そこで実行が再開される。もし エラー・ハンドラが見つからなければ、デフォルトのエラー・ハンドラが実行され、メッセージが表示され、プログラムが終了する。 プログラムを終了する。

これは我々の基準にどう合致しているのだろうか?

標準化されている-一貫した使い方がより有用になる。
これはD流であり、D言語のランタイム・ライブラリやサンプルで一貫して使われている。 ランタイム・ライブラリや例で一貫して使われている。
プログラマーがエラーのチェックを怠ったとしても、結果は妥当なものである。 エラーのチェックを怠っても、結果は妥当なものになる。
エラーに対するキャッチ・ハンドラが存在しない場合、プログラムはデフォルトのキャッチ・ハンドラによって潔く終了する。 プログラムは、デフォルトのエラー・ハンドラを通じて、適切なメッセージとともに潔く終了する。 を経由して優雅に終了する。
古いコードを新しいコードで再利用することができる。 新しいエラー型に対応するように古いコードを修正する必要がない。
古いコードは、すべてのエラーをキャッチするか、特定のエラーだけをキャッチするかを決めることができる、 残りは上方に伝搬する。いずれにせよ エラー番号とメッセージを関連付ける必要はなくなる。 が常に供給される。
不注意で無視されるエラーはない。
エラー例外は何らかの方法で処理される。エラー例外は何らかの方法で処理される。 エラーを示すNULLポインタが返され、その後にそのNULLポインタを使おうとするようなことはない。 そのNULLポインターを使おうとすることはない。
クイック&ダーティな」ユーティリティは、それでもエラーを正しく処理することができる。 を書くことができる。
クイック&ダーティなコードは、エラー処理コードを書く必要はない。 エラーをチェックする必要もない。エラーはキャッチされる、 適切なメッセージが表示され、プログラムは優雅にシャットダウンされる。 すべてデフォルトで行われる。
エラー処理のソースコードを見栄え良くするのは簡単だ。
try/catch/finally文は、エンドレスな次のような文よりもずっときれいに見える。 if (error) goto errorhandler; statements.
これは、エラーに関する私たちの仮定をどのように満たしているのだろうか?
エラーはプログラムの通常の流れの一部ではない。エラーは は例外的で、異常で、予期せぬものである。
D例外処理はまさにそれに当てはまる。
エラーは普通ではないので、エラー処理コードの実行はパフォーマンス上重要ではない。 の実行はパフォーマンス上重要ではない。
例外処理スタックの巻き戻しは比較的遅い処理である。
プログラム・ロジックの通常のフローはパフォーマンスが重要である。
通常のフロー・コードでは、すべての関数呼び出しをチェックする必要はない。 通常のフロー・コードは、エラー・リターンに対してすべての関数呼び出しをチェックする必要がないので、エラーに対して例外処理を使用する方が現実的に高速である。 例外処理を使用する方が現実的に速い。
すべてのエラーは、何らかの方法で処理されなければならない。 すべてのエラーは何らかの方法で処理されなければならない。 によって処理されなければならない。
特定のエラーに対応するハンドラーがない場合、そのエラーは次のように処理される。 ランタイム・ライブラリのデフォルト・ハンドラによって処理される。エラーが無視される場合 それは、プログラマーがエラーを無視するコードを特別に追加したからである。 エラーを無視するコードを追加したためである。
エラーを検出するコードは、エラーから回復しなければならないコードよりも、エラーについて詳しく知っている。 エラーを検出したコードは、そのエラーから回復しなければならないコードよりも、エラーについて詳しく知っている。
エラーコードを人間が読める文字列に変換する必要はもうない。 正しい文字列はエラー検出コードによって生成される。 正しい文字列はエラー回復コードではなく、エラー検出コードによって生成される。これはまた、次のことにもつながる。 アプリケーション間で同じエラーに対する一貫したエラーメッセージが生成される。
例外を使ってエラーを処理することは、別の問題につながる。 例外安全プログラムをどう書くかである。これがその方法だ。