By that I mean, what do I need to do to have useful assertions in my code?
MFC is quite easy, i just use ASSERT(something).
What\'s the non-MFC way?
The problem with "assert" is that it is usually in debug binaries, and that some developers use them as if the code would still be in production.
This is not evil per se, as the code is supposed to be intensively tested, and thus, the bugs producing the assert will surely be discovered, and removed.
But sometimes (most of the times?), the tests are not as intensive as wanted. I won't speak about an old job where we had to code until the very last minute (don't asks... Sometimes, managers are just... Ahem...)... What's the point of an assert you adding to a code that will be compiled and delivered as a Release Binary to the client the next minute?
In our team, we needed something to detect the error, and at the same time something else to handle the error. And we needed it, potentially, on Release Build.
Assert will both detect and handle the error only on debug build.
So we added instead a XXX_ASSERT macro, as well as a XXX_RAISE_ERROR macro.
The XXX_ASSERT macro would do the same thing as the ASSERT macro, but it would be built both in Debug and in Release. Its behaviour (write a log, open a messagebox, do nothing, etc.) could be controlled by a .INI file, and THEN, it would abort/exit the application.
This was used as:
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 macro would only "log" the error but would not try to handle it. This means that it could log the message in a file and/or open a MessageBox with the message , and a button to continue, and another to launch a debug session (as per .INI file config). This was used as:
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.
}
One year after their introduction in our libs, only XXX_RAISE_ERROR is being used. Of course, it can't be used on time-critical parts of the app (we have a XXX_RAISE_ERROR_DBG for that), but everywhere else, it is good. And the facts that one can use whatever prefered error handling, and that it can be activated at will, either on the developer computer, or the tester, or even the user, is quite useful.
To break inside the file that called the assert, you can use a custom macro that throws an exception or calls __debugbreak
:
#define MYASSERT(EXPR, MSG) if (!(EXPR)) throw MSG;
Or:
#define MYASSERT(EXPR) if (!(EXPR)) __debugbreak();
Microsoft-specific CRT asserts
#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());
There is a more advanced open source library called ModAssert, that has assertions that work on both Visual C++ and gcc. Probably also on other compilers, don't know for sure. It takes some time to learn it, but if you want good assertions that don't depend on MFC, look at these. It's at http://sourceforge.net/projects/modassert/
#include <cassert>
/* Some code later */
assert( true );
Asserts are used to identify runtime states that should be true. As a result, they are compiled out in release mode.
If you have a situation where you want an assert to always hit, you can pass false to it. For example:
switch ( someVal ):
{
case 0:
case 1:
break;
default:
assert( false ); /* should never happen */
}
It is also possible to pass a message through assert:
assert( !"This assert will always hit." );
Mature codebases frequently extend the assert functionality. Some of the common extensions include:
Here is my most recent iteration of an Assertion facility in C++: http://pempek.net/articles/2013/11/17/cross-platform-cpp-assertion-library/
It's a drop-in 2 files lib you can easily add to your project.