After reading some threads on misuses of exceptions (basically saying you don't want to unwind the stack if a functions preconditions are incorrect - possibly signalling that all your memory is corrupt or something equally dangerous) I'm thinking about using assert() more often. Previously I have only used assert() as a debug tool and I think this is how a lot of C++ programmers use it. I'm concerned about part of my error handling being turned off by a NDEBUG #define introduced to the runtime builds at some point in the future. Is there a way round this and have others had a problem with this (i.e. should I be worrying about it)?
Thanks, Pat
Edit: The point of the threads I was reading was that if your application is truely buggered then unwinding stack could damage the system, for instance if a destructor wrote something to a file and the file handle was corrupted. I'm not suggesting using assert for normal error handling. The current use case I have is pretty weak but see what you think:
//check later code won't crash the system
if( buf.length() % 2 )
return false;
// do other stuff that shouldn't affect bufs length
//copy 2 bytes into buf at a time, if length is odd then don't know
//what will happen so use assert to make sure it can't damage anything
assert( !(buf.length() % 2) );
for( i = 0; i != buf.length(); i += 2 )
memcpy( buf + i, data, 2 );
edit2: the discussion is here: http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/80083ac31a1188da
Well, a failing assertion is a bug, no more, no less. Same as dereferencing a null pointer, except that you yourself gave your software the stick to hit you. Brave decision, you deserve credit for it!
Jumping out of the problem with an exception hardly helps, it does not fix the bug. So I would recommend implementing your own ASSERT() macro, which:
If performance is an issue, you may consider having some kind of SOFT_ASSERT() macro that disappears from release builds.
You could build your own assert instead of using the stock C assert.h. Your assert won't be disabled.
Look at how assert() is implemented in /usr/include/assert.h (or wherever). It's simply some preprocessor magic eventually calling an "assert fail" function.
In our embedded environments, we replace assert() all the time.
I like to define my own assertion macros. I make two -- ASSERT tests always (even for optimized builds) and DASSERT only has an effect for debug builds. You probably want to default to ASSERT, but if something is expensive to test, or assertions inside inner loops of performance-sensitive areas can be changed to DASSERT.
Also, remember, that assertions should only be used for totally nonsensical conditions that indicate a logical error in your program and from which you can't recover. It's a test of your programming correctness. Assertions should NEVER be used in place of error handling, exceptions, or robustness, and you should never assert anything related to malformed or incorrect user input -- such things should be handled gracefully. An assertion is just a controlled crash where you have the opportunity to output some extra debugging info.
Here are my macros:
/// ASSERT(condition) checks if the condition is met, and if not, calls
/// ABORT with an error message indicating the module and line where
/// the error occurred.
#ifndef ASSERT
#define ASSERT(x) \
if (!(x)) { \
char buf[2048]; \
snprintf (buf, 2048, "Assertion failed in \"%s\", line %d\n" \
"\tProbable bug in software.\n", \
__FILE__, __LINE__); \
ABORT (buf); \
} \
else // This 'else' exists to catch the user's following semicolon
#endif
/// DASSERT(condition) is just like ASSERT, except that it only is
/// functional in DEBUG mode, but does nothing when in a non-DEBUG
/// (optimized, shipping) build.
#ifdef DEBUG
# define DASSERT(x) ASSERT(x)
#else
# define DASSERT(x) /* DASSERT does nothing when not debugging */
#endif
I would avoid relying on assert for other than a casual way to check assumptions during debugging. In release code, your redefined assert is going to be handled by a random crash, this is not user friendly
If during debugging, an assumption of yours, say a given condition will never be true, turns out to be invalid. Change your error handling code accodingly to take into account that condition.
Otherwise, have a more user-friendly facility for handling assumption violating conditions. Create an exception called CAssumptionViolated, throw it where you would otherwise assert. Catch it in your main routine and provide a means for the user to alert you about the error. Better yet, provide debug information with the exception. Even better, automatically forward the debug information to your organization somehow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With