8

C および C++ では、プログラムにエラーを書き込んで終了するassert非常に重いルーチンです。stdout私たちのアプリケーションでは、assert のはるかに堅牢な代替を実装し、独自のマクロを与えました。マクロを置き換えるためにあらゆる努力が払われましたが、再導入できるassert方法はまだたくさんあります(たとえば、内部のサードパーティ ライブラリ、ナイーブ インジェクションなどから)。assert

の使用を減らしたり、制限したり、根絶したりする方法について何か提案はありassertますか? 最良の答えは、コンパイラがキャッチできるものであり、現在のようにコード ベースを子守する必要はありません。

4

10 に答える 10

14

実際、問題を本当に理解しているかどうかはわかりません。アサートは、発生した場合にのみコストがかかりますが、これは例外的な状況にあるため、とにかく問題ありません。

assertはデバッグ ビルドでのみ有効になるため、サードパーティ ライブラリのリリース ビルドを使用してください。しかし、実際には、アサートは常にオフになるべきではありません。

于 2009-12-04T00:54:28.047 に答える
2

組み込みのアサーション機能を改善すると便利な場合があります (スタック トレース、コア ダンプなどを提供するため)。その場合、開発者にあなたが持っている標準(「assert()使用する代わりに」など)に従うようにさせるのに問題がある場合は、ヘッダーのコンパイラのランタイムディレクトリの前のインクルードパスに独自のヘッダーをSUPER_ASSERT()置くことができます。assert.h

これにより、標準assert()マクロを使用しているすべての人がコンパイラ エラーを受け取るか、アサーション機能を取得することがほぼ保証されます (assert.hヘッダーの内容によって異なります)。

于 2009-12-04T07:51:59.590 に答える
2

質問は有効だと思います。

私自身のアサートは、トリガーされると asm("int3") に展開されます。これはブレークポイントに相当します。また、単純な終了よりもデバッグにはるかに役立つこともわかりました。

通常の「assert()」ではなく単に「ASSERT()」と呼び、assert() の使用をまったく避けました。

于 2009-12-04T10:59:54.707 に答える
2

あなたの質問は完全に有効だと思います。独自のエラー処理を実装している場合は、次のことが必要になる場合があります。

  1. リリース ビルドでも常にアサートをトリガーします。
  2. アサートがトリガーされた場合に備えて、より適切なエラー レポートを実装します。エラー レポートを送信したり、ログ ファイルに書き込んだりすることができます。

そうは言っても、常に機能する解決策はありません。

  • #pragma once運が良ければ、サードパーティのライブラリは ASSERT マクロを使用します。このマクロを定義するファイルに何らかの種類のマクロが含まれているか#ifndef __HEADERFILE_H__ #define __HEADERFILE_H__、複数のインクルードに対する規定がある限り、このマクロを自分で再定義できます。ヘッダー ファイルを個別にインクルードし、ASSERT を再定義すれば問題ありません。

  • それらに assert.h または cassert が直接含まれている場合、私が推測するコードにのみパッチを適用できます。最小限のコード変更を行い、変更をパッチ ファイルとして保存し、ライブラリを更新するときにパッチがまだ機能することを願っています。パッチをバージョン管理に追加します。

これが機能しない場合は、サードパーティ ライブラリで内部アサートが本当に必要かどうかを再考してください。リリース ビルドのみを出荷します。これによりアサートが取り除かれ、ASSERT を追加してコード内の正確性をチェックします。戻り値の妥当性をチェックします。このような ASSERT がトリガーされた場合でも、サードパーティのコードを調べて、問題の原因を確認できます。

于 2009-12-04T10:31:10.260 に答える
1

assertサードパーティのコードが「標準」の動作を想定して記述されている可能性が最も高いという事実を見逃しているようです。つまり、コードは、アサーションが失敗したときにプログラムが終了することを期待しています。アサートされた条件が壊れている場合、通常、アサーションに続くコードは正しく機能しません。100 のうち 99 のケースでは、まったく機能しません。100 のうち 99 のケースでは、単純にクラッシュします。つまり、プログラムはとにかく終了します。

assertサードパーティのコードで動作をオーバーライドすることで、プログラムの寿命を延ばすことができると信じるのは、どう見てもナイーブです。

于 2009-12-04T07:59:55.083 に答える
1

assert()は通常、リリース コード( )に対して ((void)0) とされる#defineため、オーバーヘッドはまったくありません。#define NDEBUG

テスト バージョンを使用する場合、パフォーマンスのオーバーヘッドが原因で、テストを現実的なものにする能力が損なわれていますか?

于 2009-12-04T00:58:04.913 に答える
1

最も明白なアプローチは、独自のバージョンの assert に独自の名前を付けることですassert()。次に、テキストを検索したり、リンカ メッセージを調べたりして、リテラル文字列 "_assert" を探します。これを見れば、問題があることがわかります。

私自身のコードでAssert()は、アサーションを実行する独自の関数に展開されるか((void)0)、リリース ビルド用に展開される を常に使用します。コンパイラは((void)0)式を何も変換しませんが、それでも式としてカウントされます。したがって

Assert(3 == x);

に変わります

((void)0);

セミコロンには場所があります。

ところで、アサートが特別な GUI モーダル ポップアップ ダイアログである GUI アプリケーションに取り組んだことがあります。3 つの選択肢がありました: 無視する、永久に無視する、または中断します。Ignore は、アサートを無視して実行を続けます。永遠に無視するとフラグが設定され、デバッガーでプログラムを再起動するまで、そのアサートはそれ以上発生しません。Break は、アサートがデバッガーに割り込むことを許可します。

各アサートに独自のフラグがあることをどのように保証したか覚えていません。Assert() 呼び出しを作成したときに、一意の整数を指定する必要があったのではないでしょうか? それがもっと自動化されていればいいのに。実際の実装はビットベクトルであり、永遠に無視を選択するとビットが設定されると確信しています。

于 2009-12-04T00:52:30.337 に答える
1

ソースコードがあなたの管理下にある場合:

#define NDEBUG
// Before
#include <assert.h>
// Or other header that includes assert.h

または、プリコンパイル済みヘッダーまたはコンパイル オプションを使用して定義しますNDEBUG

サードパーティのバイナリについては、それらのリリース バージョンを使用してください。

于 2009-12-04T01:04:31.190 に答える
0

ライブラリ ヘッダーを検索assertし (ファイル システム上の実際のファイルであると仮定)、無効なものに置き換えます。

// #define assert(condition) ... /* old definition */
#define assert(condition) ((condition) & "PLEASE DO NOT USE ASSERT" = 42)
于 2009-12-04T00:55:58.287 に答える