4

Dで条件を「強制」するか、条件を「アサート」するかを選択するのに苦労しています(ただし、これは言語に依存しません)。

理論的には、アサーションを使用してバグを見つけ、他の条件を適用して非定型の条件をチェックすることを知っています。たとえば、メソッドの引数について言うかもしれませんassert(count >= 0)。これは、呼び出し元にバグがあることを示しているためです。これはenforce(isNetworkConnected)バグではないため、これは、あなたのコントロールを超えた正当な状況。

さらに、アサーションは、副作用なしに最適化としてコードから削除できますが、強制は常に条件コードを実行する必要があるため、削除することはできません。したがって、メソッドへの最初のアクセスで自分自身を埋める怠惰なコンテナを実装している場合は、enforce(!empty())代わりに言います。これは、内部のコードを怠惰に実行するため、常にassert(!empty())チェックが行われる必要があるためです。empty()

だから私は彼らが意味することになっていることを知っていると思います。しかし、理論は実践よりも簡単で、実際に概念を適用するのに苦労しています。

次のことを考慮してください。

他の2つの範囲を反復処理する範囲(イテレーターと同様)を作成し、結果を追加します。(機能プログラマーの場合:map!("a + b")代わりに使用できることは承知していますが、質問を説明していないため、今のところ無視しています。)したがって、擬似コードで次のようなコードがあります。

void add(Range range1, Range range2)
{
    Range result;
    while (!range1.empty)
    {
        assert(!range2.empty);   //Should this be an assertion or enforcement?
        result += range1.front + range2.front;
        range1.popFront();
        range2.popFront();
    }
}

それは主張か強制か?(範囲が同時に空にならないのは呼び出し元のせいですか?範囲がどこから来たのかを制御できない可能性があります-ユーザーから来た可能性があります-しかし、それでも、バグですね)

または、別の擬似コードの例を次に示します。

uint getFileSize(string path)
{
    HANDLE hFile = CreateFile(path, ...);
    assert(hFile != INVALID_HANDLE_VALUE); //Assertion or enforcement?
    return GetFileSize(hFile); //and close the handle, obviously
}
...

これはアサーションまたは強制のどちらである必要がありますか?パスはユーザーからのものである可能性があります(したがって、バグではない可能性があります)が、パスが有効であることがこのメソッドの前提条件です。主張または強制しますか?

ありがとう!

4

3 に答える 3

1

それが完全に言語に中立であるかどうかはわかりません。私が使用している 言語はありません。使用している言語に遭遇した場合は、その言語に慣用的なものである可能性がある、意図された方法で使用しenforce()たいと思います。assertenforce

たとえばassert、CまたはC ++では、プログラムが失敗したときにプログラムを停止し、例外をスローしないため、その使用法はあなたが話しているものと同じではない可能性があります。C ++で使用するassertのは、呼び出し元がすでにエラーを起こしていて、クリーンアップに頼ることができないほど重大であるか(たとえば、負のカウントを渡す)、または他のコードでエラーが発生したと思われる場合を除きます。エラーが非常に重大であるため、プログラムは未定義の状態にあると見なす必要があります(たとえば、データ構造が破損しているように見えます)。C ++は、ランタイムエラーとロジックエラーを区別します。これは大まかに対応している可能性がありますが、ほとんどの場合、回避可能なエラーと回避できないエラーについてです。

不一致のリストを提供するプログラムにバグがあり、修正が必要であることが作成者の意図である場合addは論理エラーを使用し、発生する可能性のあるものの1つにすぎない場合はランタイム例外を使用します。たとえば、関数が任意のジェネレーターを処理する場合、シーケンス全体を破壊的に評価する以外に長さを報告する手段が必ずしもない場合は、避けられないエラー状態と見なされる可能性が高くなります。

これを論理エラーと呼ぶことは、純粋な理由で長さを確認できない場合は、呼び出す前に長さを確認するのは呼び出し側の責任であることを意味します。addしたがって、最初に長さを明示的にチェックせずにユーザーからリストを渡すことはありません。正直なところ、未定義の動作ではなく例外が発生したこともあります。

これをランタイムエラーと呼ぶと、この場合に発生したことを示す例外を除いて、さまざまな長さのリストを渡すことが「合理的」(異常な場合)であることを表します。したがって、私は主張ではなく執行だと思います。

:の場合filesize、ファイルが存在する場合、可能であれば、それをバグ(アサーション)ではなく、潜在的に回復可能な障害(強制)として扱う必要があります。その理由は、ファイルが存在することを呼び出し元が確認する方法がないためです。存在の確認と呼び出しの間に、ファイルを削除したり、フィールドシステム全体をアンマウントしたりできる、より多くの特権を持つ誰かが常に存在します。filesize。したがって、それが存在しない場合、それは必ずしも呼び出し元のコードの論理的な欠陥ではありません(ただし、エンドユーザーは自分自身を足で撃った可能性があります)。その事実のために、それを発生するものの1つ、避けられないエラー状態として扱うことができる呼び出し元が存在する可能性があります。ファイルハンドルの作成もメモリ不足で失敗する可能性があります。これは、ほとんどのシステムで避けられないもう1つのエラーですが、たとえばオーバーコミットが有効になっている場合は必ずしも回復可能なエラーではありません。

考慮すべきもう1つの例は、C++のベクトルに対するoperator[]vsです。、論理エラーをスローします。これは、呼び出し元が回復したいと考える可能性がないため、またはを使用して範囲外の配列にアクセスするという間違いを犯すために何らかの無感覚である必要があるためではなく、呼び出し元はそれを望んでいます-インデックスが適切かどうかを知る他の方法がない場合は、アクセス前にいつでも確認できます。したがって、チェックをまったく保証するものではなく、効率の名目で、範囲外のアクセスには未定義の動作があります。at()at()out_of_rangeat()size()operator[]

于 2011-02-25T19:06:49.443 に答える
0

私はあなたがあなたの質問に部分的に答えたと信じています。アサーションは流れを壊すものです。あなたの主張が間違っていれば、あなたは何も続けることに同意しません。何かを強制する場合、状況に基づいて何かが起こるのを許可する決定を下しています。条件が満たされていないことがわかった場合は、特定のセクションへの入場を強制的に拒否できます。

于 2011-02-25T17:28:13.563 に答える