C ++でアサーションチェックを実装する最良の方法は何ですか?
-
05-07-2019 - |
質問
つまり、コードに有用なアサーションを含めるには何をする必要がありますか?
MFCは非常に簡単で、ASSERT(何か)を使用します。
非MFCの方法は何ですか?
編集: assert()を呼び出したファイルではなく、assert.cでアサートの中断を停止することはできますか?
編集: <assert.h>
<!> amp;の違いは何ですか? <cassert>
?
承認された回答:この投稿にはたくさんの素晴らしい回答がありますが、複数の回答を受け入れることができます(または誰かがそれらすべてを組み合わせることもできます)。したがって、回答はFerruccioに授与されます(最初の回答)。
解決
#include <cassert>
assert(something);
また、コンパイル時のチェックには、Boostの静的アサートが非常に便利です:
#include <boost/static_assert.hpp>
BOOST_STATIC_ASSERT(sizeof(int) == 4); // compile fails if ints aren't 32-bit
他のヒント
Visual C ++以外で動作するものを探しているかどうかによって異なります。また、探しているアサーションのタイプにも依存します。
アサーションにはいくつかの種類があります:
-
プリプロセッサ
これらのアサーションは、プリプロセッサディレクティブ#error
を使用して行われます プリプロセッサアサーションは前処理段階でのみ評価されるため、テンプレートなどには役立ちません。 -
実行時間
これらのアサーションは、assert()
で定義されている<cassert>
関数を使用して行われます 実行時アサーションは、実行時にのみ評価されます。また、BoltBaitが指摘したように、NDEBUG
マクロが定義されている場合はコンパイルされません。 -
静的
あなたが言ったように、これらのアサーションはASSERT()
マクロを使用して行われますが、MFCを使用している場合のみです。 C / C ++標準の一部である静的アサーションを行う別の方法は知りませんが、Boostライブラリは別のソリューションを提供します。static_assert
。
Boostライブラリの<=>関数は、 C ++に追加される予定です。 0x標準。
追加の警告として、Ferruccioが提案した<=>関数は、MFC <=>マクロと同じ動作をしません。前者は実行時アサーションで、後者は静的アサーションです。
これが役立つことを願っています!
アサートは(通常)デバッグ専用です
<!> quot; assert <!> quot;の問題通常はデバッグバイナリ内にあり、一部の開発者は、コードがまだ本番のままであるかのようにそれらを使用することです。
コードは徹底的にテストされることになっているため、これ自体は悪ではありません。したがって、アサートを生成するバグは確実に発見され、削除されます。
しかし、時々(ほとんどの場合?)、テストは必要なほど集中的ではありません。最後の最後までコーディングしなければならなかった古い仕事については語りません(質問しないでください...時々、マネージャーは... Ahem ... )...コンパイルしてリリースバイナリとしてクライアントに配信するコードに追加するアサートのポイントは何ですか?
(一部の)実際のアプリケーションでのアサート
私たちのチームでは、エラーを検出するための何かと、エラーを処理するための何かが必要でした。そして、潜在的に、リリースビルドでそれが必要でした。
Assertは、デバッグビルドでのみエラーを検出して処理します。
そのため、代わりにXXX_ASSERTマクロとXXX_RAISE_ERRORマクロを追加しました。
XXX_ASSERTマクロはASSERTマクロと同じことを行いますが、デバッグとリリースの両方でビルドされます。その動作(ログの書き込み、メッセージボックスのオープン、何もしないなど)は、.INIファイルで制御でき、その後、アプリケーションを中止または終了します。
これは次のように使用されました:
bool doSomething(MyObject * p)
{
// If p is NULL, then the app will abort/exit
XXX_ASSERT((p != NULL), "Hey ! p is NULL !") ;
// etc.
}
XXX_RAISE_ERRORマクロは<!> quot; log <!> quot;エラーが、それを処理しようとしませんでした。これは、メッセージをファイルに記録するか、メッセージ、および続行するボタン、およびデバッグセッションを起動する別のボタン(.INIファイルの構成に従って)でMessageBoxを開くことができることを意味します。これは次のように使用されました。
bool doSomething(MyObject * p)
{
if(p == NULL)
{
// First, XXX_RAISE_ERROR will alert the user as configured in the INI file
// perhaps even offering to open a debug session
XXX_RAISE_ERROR("Hey ! p is NULL !") ;
// here, you can handle the error as you wish
// Than means allocating p, or throwing an exception, or
// returning false, etc.
// Whereas the XXX_ASSERT could simply crash.
}
// etc.
}
ライブラリへの導入から1年後、XXX_RAISE_ERRORのみが使用されています。もちろん、アプリのタイムクリティカルな部分では使用できません(そのためにXXX_RAISE_ERROR_DBGがあります)が、他のどこでも、それは良いことです。また、好みのエラー処理を使用でき、開発者コンピューター、テスター、またはユーザーでさえ自由にアクティブにできるという事実は非常に便利です。
2番目の<!> quot; edit <!> quot;で質問に回答するには:
<!> lt; assert.h <!> gt; Cヘッダーです
<!> lt; cassert <!> gt; C ++標準ライブラリのヘッダーです...通常、<!> ltが含まれます。 assert.h <!> gt;
アサートを呼び出したファイル内を中断するには、例外をスローするか__debugbreak
を呼び出すカスタムマクロを使用できます:
#define MYASSERT(EXPR, MSG) if (!(EXPR)) throw MSG;
または:
#define MYASSERT(EXPR) if (!(EXPR)) __debugbreak();
基本的なアサートの使用法
#include <cassert>
/* Some code later */
assert( true );
ベストプラクティスノート
アサートは、真である必要がある実行時状態を識別するために使用されます。その結果、リリースモードでコンパイルされます。
アサートを常にヒットさせたい場合は、falseを渡すことができます。例:
switch ( someVal ):
{
case 0:
case 1:
break;
default:
assert( false ); /* should never happen */
}
assertを介してメッセージを渡すこともできます:
assert( !"This assert will always hit." );
成熟したコードベースは、アサート機能を頻繁に拡張します。一般的な拡張機能には次のものがあります。
- テストをローカライズするために、モジュールごとにアサートを切り替える。
- ほとんどのデバッグビルドでコンパイルされる追加のアサートマクロを作成します。これは、非常に頻繁に(1秒あたり数百万回)呼び出され、誤っている可能性が低いコードに適しています。
- ユーザーが現在ヒットしているアサート、コンパイルユニット内のすべてのアサート、またはコードベース内のすべてのアサートを無効にできるようにします。これにより、良性のアサートがトリガーされなくなり、使用できないビルドが作成されます。
Microsoft固有のCRTアサート
#include <crtdbg.h>
#include <sstream>
...
// displays nondescript message box when x <= 42
_ASSERT(x > 42);
// displays message box with "x > 42" message when x <= 42
_ASSERTE(x > 42);
// displays message box with computed message "x is ...!" when x <= 42
_ASSERT_EXPR(
x > 42, (std::stringstream() << L"x is " << x << L"!").str().c_str());
ModAssertと呼ばれるより高度なオープンソースライブラリがあり、Visual C ++とgccの両方で機能するアサーションがあります。おそらく他のコンパイラでも、確かにわかりません。学習するには時間がかかりますが、MFCに依存しない適切なアサーションが必要な場合は、これらを参照してください。 http://sourceforge.net/projects/modassert/
にあります。intellisenseを使用してVisual Studioで開きます(右クリック)
// cassert standard header
#include <yvals.h>
#include <assert.h>
yvals.hはWindowsのものです。したがって、assert()自体に関する限り、それを含める2つの方法は同じです。 <cxxx>
を使用することをお勧めします。多くの場合、それほど単純ではないからです(名前空間のラッピングやその他の魔法)
これは私のために発信者サイトで中断します...
記事では、このマクロを自分で書きたくない理由を説明しています。
>C ++でのアサーション機能の最近の反復です: http://pempek.net/articles/2013/11/17/cross-platform-cpp-assertion-library/
これは、プロジェクトに簡単に追加できるドロップイン2ファイルライブラリです。
質問者の3番目の質問に答えるには: <!> quot; cassert <!> quotを使用する最初の理由; <!> quot; assert.h <!> quot;の代わりにこれは、C ++の場合、C ++コンパイラーがコード記述ファイルではなく、dllまたはコンパイラー自体に関数の記述を保存できるという事実を考慮しているためです。 2つ目は、現在または将来のCとC ++の違いを容易にするために、関数に小さな変更が加えられる可能性があることです。 assert.hはCライブラリであるため、<!> quot; cassert <!> quot;を使用することをお勧めします。 C ++の場合。