4

の趣旨がわかりませんassert()

私の講師は、 assert の目的はバグを見つけることだと言っています。

例えば ​​:

double divide(int a , int b ) 
{
  assert (0 != b);
  return a/b;
}

上記の主張は正当化されますか?答えは yes だと思います。私のプログラムが0(数値ゼロ) で動作するはずがないのに、どういうわけかゼロがb変数に入る場合、コードに何か問題があるからです。

私は正しいですか?

正当化されたassert()の例をいくつか見せてもらえますか?

よろしく

4

6 に答える 6

16

assertプログラムが正しい場合に常に真であるべきことを検証するために使用されます。あなたの例で正当化されるかどうかassertは、の仕様に依存しますdivide:b != 0が前提条件である場合、assert通常はそれを確認するための推奨される方法です: 誰かが前提条件を満たさずに関数を呼び出した場合、それはプログラミングエラーであり、プログラムを終了する必要があります極端な偏見を持って、追加の作業をできるだけ少なくします。(通常、これが当てはまらないアプリケーションもあり、例外をスローして、最良の結果を期待してつまずいた方がよい場合もあります。)ただし、 の仕様でdivideは、b == 0(たとえば return +/- Inf) の場合、assert を使用する代わりにこれを実装する必要があります。

また、assert実行時間が長すぎることが判明した場合は、オフにすることもできます。ただし、一般的に、これはコードの重要なセクションでのみ、かつプロファイラーが本当に必要であると示した場合にのみ実行する必要があります。

FWIW: あなたの質問とは関係ありませんが、投稿したコード0.0divide( 1, 3 ). どういうわけか、これはあなたが望んでいたものではないと思います。

于 2012-08-28T15:04:24.993 に答える
8

アサーションのもう 1 つの側面: アサーション
は一種のドキュメントでもあります。

のようなコメントの代わりに

// ptr is never NULL
// vec has now n elements

より良い書き込み

assert(ptr!=0);
assert(vec.size()==n);

コメントは時間の経過とともに古くなり、混乱を招く可能性があります。しかし、アサーションは常に検証されます。
コメントは無視できます。アサーションはできません。

于 2012-08-28T15:55:05.940 に答える
6

assertデバッグ段階で通常使用するという事実を除いて、あなたは の評価にかなりスポットを当てていますassert...これは、製品コード中に をトリガーしたくないためですassert...例外をスローします(そして適切にそれらを処理する) は、プロダクション レベルのコードで実行時エラーを管理するための適切な方法です。

ただし、一般的には、仮定のテストにassert使用されます。デバッグ段階で想定された条件がコード内で満たされない場合、特に目的の入力に対して範囲外の値を取得している場合は、エラーが発生した時点でプログラムが救済されるようにする必要があります。それを修正できます。たとえば、ポインターを返す関数を呼び出していて、その関数がポインター値を返すべきではないとします。言い換えれば、値を返すことは単にエラー状態を示すものではなく、コードがどのように機能するかという想定が間違っていることを意味します。よく使うところですNULLNULLassert... プログラムは 1 つの方法で動作すると仮定し、そうでない場合は、そのエラーの伝播によって見つけにくいクレイジーなバグが別の場所に発生することを望まない...発生します。

最後に、ビルトイン マクロをassertas など__LINE__と組み合わせることができ__FILE__ます。これにより、アサートが発生したコード内のファイルと行番号が得られ、問題領域をすばやく特定するのに役立ちます。

于 2012-08-28T14:56:54.150 に答える
3

アサートの目的は、デバッグ中に予期しない動作を通知することです (デバッグ ビルドでのみ使用できるため)。あなたの例は、アサートの正当なケースです。次の行はおそらくクラッシュします、そこでアサートすると、その行がヒットする直前に実行を中断し、デバッグを行うオプションがあります。

これは通常、例外と並行して行われます - 何かが間違っていることを知らせるためにアサートし、例外をスローしてケースを適切に処理します (プログラムを終了する場合でも):

double divide(int a , int b ) 
{
  assert (0 != b);
  if ( b )
     return a/b;
  throw division_by_0_exception();
}

実行を継続したいが、何か問題が発生したことを通知したい場合があります。

于 2012-08-28T14:56:20.647 に答える
1

アサートは、コード実行中に不変条件をチェックするために使用されます。これらは、プログラマーが常に同じままであると想定する条件です。想定と異なる場合、コードにバグがあります。

アサートは事前条件と事後条件のチェックにも使用できます。1 つ目はコード ブロックの前にチェックされ、提供されたデータ/状態が正しいかどうかを検証し、2 つ目はいくつかの計算の結果が正しいかどうかをチェックします。これは、問題/バグがどこにあるかを絞り込むのに役立ちます:

assert( /*preconditions*/ );
/*here some algorithm - and maybe more asserts checking invariants*/
assert( /*postconditions*/ );

正当化された主張の例:

  1. 関数の戻り値を確認します。たとえば、外部 API 関数を呼び出して、プログラミング エラーの場合にのみエラー値が返されることがわかっている場合は、次のようにします。

WinAPI Thread32First 関数では、指定された LPTHREADENTRY32 構造体に dwSize フィールドが適切に割り当てられている必要があります。エラーが発生した場合は失敗します。この失敗は assert でキャッチする必要があります。

  1. 関数が何らかのデータへのポインターを受け入れる場合は、関数の先頭に assert を追加して、それが null でないことを確認します。この関数が null ポインターで機能しない場合、これは理にかなっています。

  2. タイムアウトを設定してミューテックスをロックしている場合、このタイムアウトが終了すると、アサートを使用して競合状態/デッドロックの可能性を示すことができます

...そしてもっとたくさん

asserts の良いトリックは、内部にいくつかの情報を追加することです。例:

assert(false && "このアサートの理由");

「この主張の理由」がメッセージ ボックスに表示されます

また、コンパイル中のエラーを示す静的アサートもあることに注意してください。

于 2012-08-28T15:17:55.163 に答える
1

アサートは、デバッグ環境でコードに関する仮定をテストするために使用されます。通常、アサートは最終的なビルドには影響しません。

それが有効なテストであるかどうかは、まったく別の問題です。あなたのアプリケーションに関する詳細な知識がなければ、私たちはそれに答えることができません.

アサートは決して失敗してはなりません。アサーションが失敗する可能性がある場合は、代わりに if ステートメントを使用して、条件が真でない場合を処理する必要があります。アサーションは、絶対に失敗しないと思われる条件のみを対象としています。

于 2012-08-28T14:57:48.357 に答える