私は最近、コードにいくつかのアサートを追加し始めました。これが私が行ってきた方法です。
コードを境界コードと内部コードに精神的に分割します。境界コードは、ユーザー入力を処理し、ファイルを読み取り、ネットワークからデータを取得するコードです。このコードでは、入力が有効な場合 (インタラクティブなユーザー入力の場合) にのみ終了するループで入力を要求するか、回復不能なファイル/ネットワークの破損データの場合に例外をスローします。
内部コードは他のすべてです。たとえば、クラスで変数を設定する関数は、次のように定義できます。
void Class::f (int value) {
assert (value < end);
member = value;
}
ネットワークから入力を取得する関数は次のようになります。
void Class::g (InMessage & msg) {
int const value = msg.read_int();
if (value >= end)
throw InvalidServerData();
f (value);
}
これにより、2 層のチェックが得られます。実行時にデータが決定されるものはすべて、常に例外または即時のエラー処理を取得します。ただし、ステートメントで追加のチェックをClass::f
行うassert
ということは、何らかの内部コードで が呼び出された場合Class::f
でも、サニティ チェックが行われることを意味します。私の内部コードは有効な引数を渡さない可能性があります (value
複雑な一連の関数から計算した可能性があるため)。そのため、設定関数にアサーションを設定して、関数を呼び出している人に関係なく、value
またはに等しいend
。
これは、私がいくつかの場所で読んでいるものに当てはまるようです。アサーションは、正常に機能するプログラムで違反することは不可能であるべきですが、例外はまだ可能である例外的で誤ったケースのためのものであるべきです。理論的にはすべての入力を検証しているため、アサーションがトリガーされることはありません。もしそうなら、私のプログラムは間違っています。