20

私は以前、主任アーキテクト/開発者の何人かがさまざまなプロジェクトでアサーションを使用しないことを義務付けていた会社で働いていました。アサーションは定期的にコードから削除され、例外に置き換えられていました。

正しいコードを書く上で非常に重要だと思います。そのような義務がどのように正当化されるかを誰かが提案できますか? もしそうなら、アサーションの何が問題なのですか?

4

11 に答える 11

20

JaredPar のコメントに従って、コントラクトのように機能する assert の修正バージョンを使用します。このバージョンはリリース コードにコンパイルされるため、サイズのオーバーヘッドは小さくなりますが、診断スイッチが設定されていない限り無効になり、パフォーマンスのオーバーヘッドが最小限に抑えられます。このインスタンスの assert ハンドラーは、無効、サイレント モード (例: ファイルへのログ)、またはノイジー モード (例: 中止/無視を使用して画面に表示し、中止によって例外がスローされる) に設定できます。

リリース前のテストの一環として自動回帰テストを使用しました。アサートは、GUI レベルでは検出できず、最初はユーザー レベルでは致命的ではない可能性のある潜在的な内部エラーを見つけることができるため、ここでは非常に重要です。自動化により、診断の有無にかかわらずテストを実行でき、実行時間以外のオーバーヘッドはほとんどないため、アサートに他の副作用があるかどうかも判断できます。

アサーションで注意すべきことの 1 つは、副作用です。たとえば、assert(MyDatabasesIsOk())のようなものが表示されることがあります。これは、データベースのエラーを誤って修正します。アサートは実行中のアプリケーションの状態を決して変更しないため、これはバグです。

于 2009-01-07T08:19:12.333 に答える
6

アサーションについて私が言える唯一の否定的なことは、アサーションが市販のコードで実行されないことです。このため、私たちのチームではアサーションを避ける傾向があります。代わりに、リテールとデバッグの両方で実行されるアサーションであるコントラクトを使用します。

現在、アサーションを使用するのは、次のいずれかが true の場合のみです。

  1. アサーション コードはパフォーマンスに顕著な影響を与えます
  2. 特定の状態は致命的ではありません
  3. 場合によっては、死んでいるかもしれないし、死んでいないかもしれないコード片があります。基本的に「どうやってここに来たのか」というアサーションを追加します。起動しないからといって、コードが実際に死んでいるわけではありませんが、QA からメールで「このアサーションはどういう意味ですか」と言われた場合は、特定のコードに到達するための再現ができました (もちろん、すぐに文書化されます)。
于 2009-01-07T06:44:49.763 に答える
5

アサーションと例外は、2 つの異なる目的で使用されます。

アサーションは、発生してはならない状態に使用されます。たとえば、signalton ポインターを null にすることはできません。このエラーは、アサートを使用して開発中に検出する必要があります。例外でそれを処理することは、無駄に多くの作業です。

一方、例外は、アプリケーションの通常の実行中に発生する可能性のあるまれな状態に使用されます。たとえば、fopen を使用すると、null ポインターが返されます。発生する可能性がありますが、ほとんどの場合、有効なポインターが返されます。

アサーションを使用することは間違っているわけでも正しくないわけでもありませんが、最終的にはプログラミングを容易にするツールであり、他のツールに置き換えることができるため、個人の好みに帰着します。

于 2009-01-07T06:41:47.960 に答える
4

これは、システムの重要度によって異なります。アサーションはフェイルファスト戦略ですが、システムが何らかの回復を実行できる場合は例外を使用できます。

たとえば、銀行のアプリケーションや通信システムではアサーションを使用しません。例外をスローします。これは、コールスタックの上位でキャッチされます。そこで、リソースをクリーンアップし、次の呼び出し/トランザクションを処理できます。1つだけが失われます。

于 2009-01-07T09:48:55.493 に答える
3

アサーションは優れた機能ですが、パラメーター/戻り値のチェックと混同しないでください。発生すると予想される状況ではなく、発生しないと思われる状況でそれらを使用します。

defaultそれらを使用する私のお気に入りの場所は、実際には到達switchしてはならないコード ブロックcaseです。

列挙型を新しい値で拡張することは比較的一般的ですが、列挙switch型を含むすべてのステートメントを更新しないでください。できるだけ早くそれを知りたいと思うでしょう。そのような状況では、激しく素早く失敗することが最善の方法です。

確かに、それらの場所では、通常、製品ビルドでも壊れるものが必要です。abort()しかし、そのような条件下での ing の原則は強く推奨されます。デバッガーで適切なスタック トレースを行うと、推測するよりも早くバグを修正するための情報が得られます。

于 2009-01-07T10:08:17.653 に答える
1

アサーションは NDEBUG を定義しないだけでそのままにしておくことができるので、実際には問題になりません。

本当の問題は、アサーションが abort() を呼び出し、プログラムを即座に停止させることです。プログラムが終了する前に実行しなければならない重要なクリーンアップがある場合、これは問題を引き起こす可能性があります。例外には、例外がキャッチされない場合でも、デストラクタが適切に呼び出されるという利点があります。

その結果、クリーンアップが本当に重要な場合は、例外の方が適切です。それ以外の場合、アサーションは問題ありません。

于 2009-01-07T08:43:35.593 に答える
1

唯一の推測は、例外は多くの場合致命的ではないため、コードベースが奇妙な状態で死ぬことはないということです。反論は、アサーションの致命性が問題の場所を示しているため、デバッグが容易であるということです。

個人的には、アサーションのリスクを冒すことを好みます。これは、デバッグが容易で予測可能なコードにつながると感じているからです。

于 2009-01-07T06:53:08.983 に答える
1

デバッグ ビルドにはアサーションが存在するが、リリース ビルドには存在しないというのは本当ですか?

何かを検証/アサートしたい場合は、デバッグ ビルドだけでなくリリース ビルドでも行いたいと思いませんか?

于 2009-01-07T06:41:01.690 に答える
0

One reason to veto assert() is that it's possible to write code that works correctly when NDEBUG is defined, but fails when NDEBUG is not defined. Or vice versa.

It's a trap that good programmers shouldn't fall into very often, but sometimes the causes can be very subtle. For example, the code in the assert() might nudge memory assignments or code positions in the executable such that a segmentation fault that would happen, does not (or vice versa).

Depending on the skill level of your team, it can be a good idea to steer them away from risky areas.

于 2009-01-07T10:11:17.397 に答える
0

デストラクタで例外をスローすることは未定義の動作であることに注意してください。

于 2009-02-26T14:12:00.070 に答える