Avoiding warnings for unused variables when using assert () in the Release assembly

Sometimes a local variable is used for a single purpose - to check it in the assert () file, for example, like this:

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

When compiling code in the Release assembly, assert () s is usually disabled, so this code may cause a warning that Result is installed, but never read.

A possible workaround is

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

But this requires too much typing, not so easy in the eyes and makes the condition always checked (yes, the compiler can optimize the check, but still).

I am looking for an alternative way to express this statement () in such a way that it does not raise a warning, but is still easy to use and does not change the semantics of assert ().

(disabling warnings with #pragma in this area of ​​code is not an option, and lowering alert levels to make it go away is not an option ...).

+48
c ++ assertions warnings
Apr 22 '09 at 13:43
source share
16 answers

We use a macro to indicate when something is not in use:

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

Then in your example you will have:

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

Thus (a) the production assembly is completed successfully, and (b) in the code it is obvious that the variable is not used by the design, and not what it was forgotten about. This is especially useful when parameters for a function are not used.

+48
Apr 22 '09 at 14:02
source share
β€” -

I would not be able to give a better answer than this, which solves this problem and much more:

Stupid C ++ Tricks: Assertion Adventures

 #ifdef NDEBUG #define ASSERT(x) do { (void)sizeof(x);} while (0) #else #include <assert.h> #define ASSERT(x) assert(x) #endif 
+19
Jun 12 '09 at 9:25
source share

You can create another macro that avoids the use of a temporary variable:

 #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); 
+9
Apr 22 '09 at 15:53
source share
 int Result = Func(); assert( Result == 1 ); 

This situation means that in release mode you really want:

 Func(); 

But Func is void, i.e. It returns the result, i.e. This is a request .

Presumably, in addition to returning the result, Func modifies something (otherwise, why worry about calling it and not using its result?), T. E. This is a command .

According to the principle of separation of request commands (1) Func should not be both a command and a request. In other words, the queries should not have side effects, and the β€œresult” of the commands should be represented by available queries in the state of the object.

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

Better than

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

The former does not give you any warnings about your race, the latter does.

So, in short, my answer is: do not write such code :)

Update (1): You requested links to the principle of separation of commands and requests . Wikipedia is pretty informative. I read about this design technique in Object Oriented Software Construction, 2nd Editon by Bertrand Meyer.

Update (2): comments by j_random_hacker "OTOH, every function" f "that previously returned a value should now set some variable last_call_to_f_succeeded or similar." This is true only for functions that promise nothing in their contract, i.e. functions that may or may not succeed, or a similar concept. With Design by Contract, the corresponding number of functions will have postconditions , so after "Empty ()" the object will be "IsEmpty ()", and after "Encode ()" the message line will be "IsEncoded ()", there is no need to check. Similarly, and somewhat symmetrically, you do not call the special function "IsXFeasible ()" before each call to the procedure "X ()"; because you usually know by design that you are fulfilling the X preconditions at the time of your call.

+8
Apr 22 '09 at 14:25
source share

You can use:

 Check( Func() == 1 ); 

And implement the bool function as you like. It can either use assert, or throw a specific exception, write to a log file or to the console, have different implementations in debugging and release, or a combination of all.

+3
Apr 22 '09 at 2:30 p.m.
source share

This is a bad use of assert, IMHO. The statement is not intended as a means of reporting errors; it means the approval of preconditions. If Result is not used elsewhere, this is not a prerequisite.

+2
Apr 22 '09 at 13:50
source share

The simplest is only declaring / assigning these variables, if statements exist. The NDEBUG macro NDEBUG defined if statements fail (this is done because -DNDEBUG is a convenient way to disable debugging, I think), so this modified copy of @Jardel's answer should work (cf. @AdamPeterson's comment on this answer):

 #ifndef NDEBUG int Result = #endif Func(); assert(Result == 1); 

or, if this does not suit your tastes, all kinds of options are possible, for example. this is:

 #ifndef NDEBUG int Result = Func(); assert(Result == 1); #else Func(); #endif 

In general, with this material, be careful that it will never be possible to create different translation units with different NDEBUG - especially re. claims or other conditional content in public header files. The danger is that you or your library users could accidentally create another definition of the built-in function from the one used inside the compiled part of the library, quietly violating one rule of definition and execution of undefined runtime behavior.

+2
Feb 04 '17 at 13:34 on
source share

You must move the statement inside the function before the return value (s). You know that the return value is not a local area network without links.

Plus, in any case, it makes sense to be inside a function, because it creates an autonomous unit that has its OWN pre-conditions and post-conditions.

Most likely, if the function returns a value, you will still need to do some error checking in release mode on this return value. Thus, this should not be an unreferenced variable.

Edit, but in this case the post-state should be X (see comments):

I strongly disagree with this point, you need to be able to determine the state of the message from the input parameters, and if it is a member function, any state of the object. If a global variable changes the output of a function, the function must be restructured.

+1
Apr 22 '09 at 13:56
source share

Of course, you use a macro to control the definition of assert, for example, "_ASSERT". So you can do this:

 #ifdef _ASSERT int Result = #endif /*_ASSERT */ Func(); assert(Result == 1); 
+1
Aug 27 2018-12-12T00:
source share

Most answers suggest using the static_cast<void>(expression) trick in the Release lines to suppress the warning, but this is actually suboptimal if you intend to do validation checks really Debug - only. The objectives of the approval macro are:

  • Perform Debug Checks
  • Do nothing in Release mode
  • Do not issue warnings in all cases

The problem is that the void-cast method does not reach the second goal. Although there is no warning, the expression you passed to the approval macro will still be evaluated. If you, for example, just do a variable check, this probably doesn't matter much. But what if you call some function in your statement validation, for example, ASSERT(fetchSomeData() == data); (which is very common in my experience)? The fetchSomeData() function will still be called. It may be quick and easy, or it may not.

What you really need is not only a warning, but, perhaps more importantly, not an evaluation of the validation expression, only debugging. This can be achieved with a simple trick, which I took from the Assert specialized library:

 void myAssertion(bool checkSuccessful) { if (!checkSuccessful) { // debug break, log or what not } } #define DONT_EVALUATE(expression) \ { \ true ? static_cast<void>(0) : static_cast<void>((expression)); \ } #ifdef DEBUG # define ASSERT(expression) myAssertion((expression)) #else # define ASSERT(expression) DONT_EVALUATE((expression)) #endif // DEBUG int main() { int a = 0; ASSERT(a == 1); ASSERT(performAHeavyVerification()); return 0; } 

All magic is in the DONT_EVALUATE macro. Obviously, at least logically, evaluating your expression is never needed inside it. To reinforce this, the C ++ standard ensures that only one of the branches of the conditional statement will be evaluated. Here is a quote:

5.16 Conditional operator [expr.cond]

boolean or expression? expression: assignment-expression

Group conditional expressions from right to left. The first expression is contextually converted to bool. It is evaluated, and if so, the result of the conditional expression is the value of the second expression, in contrast to the third expression. Only one of these expressions is evaluated.

I tested this approach in GCC 4.9.0, clang 3.8.0, VS2013 Update 4, VS2015 Update 4 with the most stringent warning levels. In all cases, there are no warnings, and the validation expression is never evaluated in the Release build (in fact, all this is fully optimized). Do not forget that with this approach you will quickly run into trouble if you place expressions that have side effects inside the statement macro, although this is, first of all, a very bad practice.

In addition, I would expect static analyzers to warn that "the result of an expression is always constant" (or something similar) with this approach. I tested this with the clang, VS2013, VS2015 static analysis tools and did not receive any warnings of this kind.

+1
Apr 23 '16 at 11:44
source share
 int Result = Func(); assert( Result == 1 ); Result; 

This will cause the compiler to stop complaining about a result that is not used.

But you should consider using an assert version that does something useful at runtime, such as descriptive log errors, in a file that can be extracted from the production environment.

0
Apr 22 '09 at 14:12
source share

I would use the following:

 #ifdef _DEBUG #define ASSERT(FUNC, CHECK) assert(FUNC == CHECK) #else #define ASSERT(FUNC, CHECK) #endif ... ASSERT(Func(), 1); 

Thus, to build a release, the compiler does not even need to create code for approval.

0
Apr 22 '09 at 15:42
source share

If this code is inside the function, then act and return the result:

 bool bigPicture() { //Check the results bool success = 1 != Func(); assert(success == NO, "Bad times"); //Success is given, so... actOnIt(); //and return success; } 
0
05 Oct '14 at 19:41
source share
 // Value is always computed. We also call assert(value) if assertions are // enabled. Value is discarded either way. You do not get a warning either // way. This is useful when (a) a function has a side effect (b) the function // returns true on success, and (c) failure seems unlikely, but we still want // to check sometimes. template < class T > void assertTrue(T const &value) { assert(value); } template < class T > void assertFalse(T const &value) { assert(!value); } 
0
Feb 19 '18 at 3:36
source share

With c ++ 17 we can do:

 [[maybe_unused]] int Result = Func(); 

although this requires a bit of extra typing compared to assert substitution. See this answer .

Note: this is added because this is the first google hit for "c ++ assert unused variable".

0
Oct 10 '18 at 16:07
source share

With recent C ++, I would simply say:

 [[maybe_unused]] int Result = Func(); assert( Result == 1 ); 

See https://en.cppreference.com/w/cpp/language/attributes/maybe_unused for more information on this attribute.

Compared to the (void)Result trick, I like it more because you directly decorate the variable declaration, and not just add something as a belated thought.

0
Dec 20 '18 at 8:39
source share



All Articles