Unique assertions

Zoppo
CERTIFIED EXPERT
Published:
Updated:
Assertions are very helpful to find problems or bugs. But, sometimes there's a problem
using them, for example within a loop or a very often called function, because if such an
assertion fails it may happen that tons of assertion-dialogs pop up (at least in VC++
with 'ASSERT'-macro that's quite a mess).

The following macro can be used easily just the same way as VC++'s 'ASSERT'-macro or
CRT's 'assert'. To make its usage thread-safe first I introduce a simple class which does
synchronization using a mutex in Windows - if you want to use the macro with other
OS you'll have to adapt that class:

 
class Lock
                      {
                      	HANDLE	GetMutex()
                      	{
                      		static HANDLE hMutex = ::CreateMutex( NULL, FALSE, NULL );
                      		return hMutex;
                      	} 
                      public:
                      	Lock()
                      	{
                      		::WaitForSingleObject( GetMutex(), INFINITE );
                      	} 
                      	~Lock()
                      	{
                      		::ReleaseMutex( GetMutex() );
                      	}
                      };

Open in new window


Here's the macro itself:

 
// Handle the first time the assertion fails
                      #define assert_once_out_first( x ) \
                      	std::cout << __FILE__ << "(" << __LINE__ << "): first assertion for expression '" << #x << "'" << std::endl; 
                      // Handle further assertion fails
                      #define assert_once_out_next( x ) \
                      	std::cout << __FILE__ << "(" << __LINE__ << "): known assertion for expression '" << #x << "'" << std::endl; 
                      // Generates a file-wide unique variable name
                      #define assert_once_var __bAsserted__ ## __LINE__ ## __ 
                      // The unique assert macro
                      #define assert_once( x ) \
                      	do { \
                      		Lock _lock; \
                      		static bool assert_once_v = false; \
                      		if ( !(x) ) \
                      		{ \
                      			if ( !assert_once_v ) \
                      			{ \
                      				assert_once_v = true; \
                      				assert_once_out_first( x ); \
                      			} \
                      			else \
                      			{ \
                      				assert_once_out_next( x ); \
                      			} \
                      		} \
                      	} while ( 0 )

Open in new window


The usage is just simple, i.e.:

> int _tmain( int argc, char* argv[] )
> {
>      for ( int i = 0; i < 3; i++ )
>      {
>            assert_once( i < 2 );
>
>            for ( int j = 0; j < 3; j++ )
>            {
>                  assert_once( j % 2 != 1 );
>            }
>      }
>
>
>      return -1;
>}

The output will be:

> c:\test\testassert.cpp(15): first assertion for expression 'j % 2 != 1'
> c:\test\testassert.cpp(15): known assertion for expression 'j % 2 != 1'
> c:\test\testassert.cpp(11): first assertion for expression 'i < 2'
> c:\test\testassert.cpp(15): known assertion for expression 'j % 2 != 1'


For VC++ it's even simple to use the macros ASSERT and TRACE by just replacing these
two macros as shown here:

> #define assert_once_out_first( x ) \
>       TRACE( "%s(%d): Assertion for expression '%s'\n", __FILE__, __LINE__, #x ); \
>       ASSERT( x );
>
> #define assert_once_out_next( x ) \
>       TRACE( "%s(%d): Known assertion for expression '%s'\n", __FILE__, __LINE__, #x ); \
1
2,140 Views
Zoppo
CERTIFIED EXPERT

Comments (2)

evilrixEngineering Manager
CERTIFIED EXPERT

Commented:
Nice Zoppo. My only comment would be that as it stands this wouldn't be thread safe without additional mutual exclusion support.
CERTIFIED EXPERT

Author

Commented:
Thanks, evilrix, and yes, you're right - I didn't add this because I wanted to keep the first version compiler-/platform independant.

I will think about how to do it best. In fact the implementation I implemented for use in my company is thread-safe.

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.