69

assert() でローカル変数をチェックするという唯一の目的で、ローカル変数が使用されることがあります。

int Result = Func();
assert( Result == 1 );

リリース ビルドでコードをコンパイルする場合、通常は assert() が無効になっているため、このコードは Result が設定されているが読み込まれないという警告を生成する場合があります。

考えられる回避策は -

int Result = Func();
if ( Result == 1 )
{
    assert( 0 );
}

しかし、それはあまりにも多くのタイピングを必要とし、目に優しくなく、条件が常にチェックされる原因になります (はい、コンパイラーはチェックを最適化するかもしれませんが、それでも)。

この assert() を、警告を発生させずに簡単に使用でき、assert() のセマンティクスを変更しないように表現する別の方法を探しています。

(このコード領域で #pragma を使用して警告を無効にすることはオプションではなく、警告レベルを下げて警告をなくすこともオプションではありません...)。

4

16 に答える 16

58

マクロを使用して、何かが未使用の場合を具体的に示します。

#define _unused(x) ((void)(x))

次に、あなたの例では、次のようになります。

int Result = Func();
assert( Result == 1 );
_unused( Result ); // make production build happy

そうすれば、(a)本番ビルドが成功し、(b)変数が設計によって使用されていないことがコードで明らかであり、単に忘れられているだけではありません。これは、関数のパラメーターが使用されていない場合に特に役立ちます。

于 2009-04-22T14:02:20.923 に答える
33

その問題に対処する、これよりも良い答えを出すことはできません。

ばかげた C++ のトリック: assert の冒険

#ifdef NDEBUG
#define ASSERT(x) do { (void)sizeof(x);} while (0)
#else
#include <assert.h>
#define ASSERT(x) assert(x)
#endif
于 2009-06-12T09:25:23.900 に答える
9

一時変数の使用を回避できる別のマクロを作成できます。

#ifndef NDEBUG
#define Verify(x) assert(x)
#else
#define Verify(x) ((void)(x))
#endif

// asserts that Func()==1 in debug mode, or calls Func() and ignores return
// value in release mode (any braindead compiler can optimize away the comparison
// whose result isn't used, and the cast to void suppresses the warning)
Verify(Func() == 1);
于 2009-04-22T15:53:18.770 に答える
8
int Result = Func();
assert( Result == 1 );

この状況は、リリース モードで、次のことが本当に必要であることを意味します。

Func();

ただしFunc、非 void です。つまり、結果を返します。つまり、クエリです。

おそらく、結果を返すFuncだけでなく、何かを変更します (そうでなければ、わざわざ呼び出してその結果を使用しないのはなぜでしょうか?)、つまり、それはcommandです。

コマンドとクエリの分離原則(1) により、Func同時にコマンドとクエリであってはなりません。言い換えれば、クエリには副作用があってはならず、コマンドの「結果」は、オブジェクトの状態に関する利用可能なクエリによって表されるべきです。

Cloth c;
c.Wash(); // Wash is void
assert(c.IsClean());

よりも良い

Cloth c;
bool is_clean = c.Wash(); // Wash returns a bool
assert(is_clean);

前者はあなたの種類の警告を与えませんが、後者は与えます。

要するに、私の答えは次のとおりです:このようなコードを書かないでください:)

更新 (1): Command-Query Separation Principleに関する参照を求めました。ウィキペディアはかなり有益です。この設計手法については、Bertrand Meyer によるObject Oriented Software Construction, 2nd Editionで読みました。

更新 (2): j_random_hacker は、「OTOH、以前に値を返したすべての「コマンド」関数 f() は、何らかの変数 last_call_to_f_succeeded などを設定する必要がある」とコメントしています。これは、コントラクトで何も約束しない関数、つまり「成功する」かどうかの可能性のある関数、または同様の概念にのみ当てはまります。Design by Contractでは、関連する数の関数に事後条件があるため、"Empty()" の後のオブジェクトは "IsEmpty()" になり、"Encode()" の後のメッセージ文字列は "IsEncoded()" になります。チェックする必要はありません。同様に、また幾分対称的に、プロシージャー「X()」を呼び出すたびに、その前に特別な関数「IsXFeasible()」を呼び出さないでください。

于 2009-04-22T14:25:59.870 に答える
4

あなたが使用することができます:

Check( Func() == 1 );

必要に応じて Check( bool ) 関数を実装します。アサートを使用するか、特定の例外をスローするか、ログ ファイルまたはコンソールに書き込むか、デバッグとリリースで異なる実装を使用するか、すべてを組み合わせます。

于 2009-04-22T14:30:40.530 に答える
2

戻り値の前に、関数内でアサートを移動する必要があります。戻り値が参照されていないローカル変数ではないことを知っています。

さらに、関数内にある方が理にかなっています。これは、独自の事前条件と事後条件を持つ自己完結型のユニットを作成するためです。

関数が値を返している場合は、とにかくこの戻り値に対してリリースモードで何らかのエラーチェックを実行する必要があります。したがって、そもそも参照されていない変数であってはなりません。

編集しますが、この場合、投稿条件はXである必要があります(コメントを参照)。

私はこの点に強く反対します。入力パラメーターからpost条件を判別でき、それがメンバー関数の場合は任意のオブジェクト状態を判別できるはずです。グローバル変数が関数の出力を変更する場合は、関数を再構築する必要があります。

于 2009-04-22T13:56:59.267 に答える
1

これは assert の悪い使い方です。Assert はエラー報告ツールではなく、前提条件をアサートするためのものです。Result が他の場所で使用されていない場合、それは前提条件ではありません。

于 2009-04-22T13:50:43.870 に答える
1

確かに、「_ASSERT」などのアサート定義を制御するためにマクロを使用します。したがって、これを行うことができます:

#ifdef _ASSERT 
int Result =
#endif /*_ASSERT */
Func();
assert(Result == 1);
于 2012-08-27T22:55:13.583 に答える
0

私は以下を使用します:

#ifdef _DEBUG
#define ASSERT(FUNC, CHECK) assert(FUNC == CHECK)
#else
#define ASSERT(FUNC, CHECK)
#endif

...

ASSERT(Func(), 1);

このように、リリース ビルドの場合、コンパイラはアサート用のコードを生成する必要さえありません。

于 2009-04-22T15:42:54.210 に答える
0

このコードが関数内にある場合は、実行して結果を返します。

bool bigPicture() {

   //Check the results
   bool success = 1 != Func();
   assert(success == NO, "Bad times");

   //Success is given, so...
   actOnIt();

   //and
   return success;
}
于 2014-10-05T19:41:19.847 に答える
0
int Result = Func();
assert( Result == 1 );
Result;

これにより、コンパイラは Result が使用されていないことについて不平を言うのをやめます。

ただし、運用環境から取得できるファイルに記述的なエラーを記録するなど、実行時に役立つバージョンの assert を使用することを検討する必要があります。

于 2009-04-22T14:12:42.943 に答える