release build assertions/verifications

A

Angel Tsankov

I need to make verifications in release builds. If a verification
fails, an error message should be displayed and the program should be
aborted. I need this solution to be portable. Then I thought of the
assert macro - it provides the desired functionality but only if
NDEBUG is not defined. So, I could write smth like this:

#if defined NDEBUG
#undef NDEBUG
#include <cassert>
#define NDEBUG
#else
#include <cassert>
#endif

Unfortunately, NDEBUG could be defined to something meaningful, in
which case it's value would be lost.

Can anyone think of some other way to use the assert macro for
verification?
What about any other options?

Regards,
Angel Tsankov
 
M

mlimber

Angel said:
I need to make verifications in release builds. If a verification
fails, an error message should be displayed and the program should be
aborted. I need this solution to be portable. Then I thought of the
assert macro - it provides the desired functionality but only if
NDEBUG is not defined. So, I could write smth like this:

#if defined NDEBUG
#undef NDEBUG
#include <cassert>
#define NDEBUG
#else
#include <cassert>
#endif

Unfortunately, NDEBUG could be defined to something meaningful, in
which case it's value would be lost.

Can anyone think of some other way to use the assert macro for
verification?
What about any other options?

Regards,
Angel Tsankov

I have implemented my own macros, which are similar to Microsoft's.
Something like:

class MyException
{
MyException( const char* msg );
const char* what() const;
};

#define VERIFY(cond) if(cond); else throw MyException( #cond )
#if defined( NDEBUG )
# define ASSERT(cond) VERIFY(cond)
#else
# define ASSERT(cond)
#endif

Of course, you can make your VERIFY do something other than throw an
exception. Remember to use compile-time assertions wherever possible
instead of run-time assertions.

Cheers! --M
 
A

Angel Tsankov

mlimber said:
I have implemented my own macros, which are similar to Microsoft's.
Something like:

class MyException
{
MyException( const char* msg );
const char* what() const;
};

#define VERIFY(cond) if(cond); else throw MyException( #cond )
#if defined( NDEBUG )
# define ASSERT(cond) VERIFY(cond)
#else
# define ASSERT(cond)
#endif

Of course, you can make your VERIFY do something other than throw an
exception.

I want my VERIFY to display a message and abort the program. The
problem is where to display the message - send it to std::cerr, use a
message box, file or what? It would also be nice if the solution is
portable. The assert macro takes care of where to output the message
and is portable. That's why I'm considering it. However, as I
mentiond, there is a slight problem with it - its value can get lost
when I #undef it. So, I'm asking for ideas how to cope with this
problem. I'd also appreciate any other relevant ideas.
 
M

mlimber

Angel said:
I want my VERIFY to display a message and abort the program. The
problem is where to display the message - send it to std::cerr, use a
message box, file or what? It would also be nice if the solution is
portable. The assert macro takes care of where to output the message
and is portable. That's why I'm considering it. However, as I
mentiond, there is a slight problem with it - its value can get lost
when I #undef it. So, I'm asking for ideas how to cope with this
problem. I'd also appreciate any other relevant ideas.

My relevant idea was given in the previous post. Just substitute your
desired behavior for the throwing of the exception. You could output to
std::cerr and call std::exit, for instance.

Cheers! --M
 
A

Angel Tsankov

mlimber said:
My relevant idea was given in the previous post. Just substitute
your
desired behavior for the throwing of the exception. You could output
to
std::cerr and call std::exit, for instance.

Output to std:cerr gets "lost" in GUI-based applications.
 
M

mlimber

Angel said:
Output to std:cerr gets "lost" in GUI-based applications.

The problem is not that cerr is not portable but that GUIs aren't.
Another portable alternative is writing to a log file, but personally,
I think throwing an exception that contains the error message (see my
first post) is the cleanest option. In such a case, you use the same
error reporting tool in the code, but supply an appropriate handler for
each platform, e.g.:

// For some GUI API
try
{
DoSomething();
}
catch( const MyException& e )
{
DialogBox( string("Error: ") + e.what() + " Terminating." );
exit( -1 );
}

// For some console application
try
{
DoSomething();
}
catch( const MyException& e )
{
cerr << ""Error: " << e.what() << " Terminating" << endl;
exit( -1 );
}

// For some program with no console attached
try
{
DoSomething();
}
catch( const MyException& e )
{
ofstream log( "log.txt", ios::app );
log << ""Error: " << e.what() << " Terminating" << endl;
exit( -1 );
}

Cheers! --M
 
A

Angel Tsankov

mlimber said:
The problem is not that cerr is not portable but that GUIs aren't.
Another portable alternative is writing to a log file, but
personally,
I think throwing an exception that contains the error message (see
my
first post) is the cleanest option.

The reason why I'd rather avoid this approach is that I am concerned
about using it in dtors.
 
M

mlimber

Angel said:
The reason why I'd rather avoid this approach is that I am concerned
about using it in dtors.

Then, perhaps the best solution is an ostream-based log. You could
accept an ostream reference or (smart) pointer in your classes'
constructors, and they could use it to write their messages. Then on
different platforms, you could pass the ostream-type object (e.g.,
std::cerr, a std::eek:fstream for a log file, a std::stringstream) that
best suits that platform.

Cheers! --M
 
A

Angel Tsankov

mlimber said:
Then, perhaps the best solution is an ostream-based log. You could
accept an ostream reference or (smart) pointer in your classes'
constructors, and they could use it to write their messages.

Well, I'm sorry to tell you but I can see another flaw with your
suggestion - my class cannot have a default ctor.
 
M

mlimber

Angel said:
Well, I'm sorry to tell you but I can see another flaw with your
suggestion - my class cannot have a default ctor.

So what's the problem? If you followed the plan mentioned above, there
would be no default constructor.

Cheers! --M
 
A

Angel Tsankov

mlimber said:
So what's the problem? If you followed the plan mentioned above,
there
would be no default constructor.

This exactly is the problem - my class cannot have a default ctor. A
default ctor is needed to create an array of objects of a UDT. So, if
I adopt your plan then I cannot have an array of objects of my class.
 
M

mlimber

Angel said:
This exactly is the problem - my class cannot have a default ctor. A
default ctor is needed to create an array of objects of a UDT. So, if
I adopt your plan then I cannot have an array of objects of my class.

OIC. I read your previous post to mean that your class *shouldn't* have
a default constructor. Sorry.

There are several ways to get around that problem. One is to use a
std::vector rather than arrays (which are evil) so that you can choose
a different constructor. See this FAQ:

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.5

Another is to use a static member variable to point to the log that can
be used for all objects of each class. The log could be set at the
declaration and/or via a static member function, .e.g.:

class MyClass
{
static boost::shared_ptr<ostream> log_;
public:
static SetLog( boost::shared_ptr<ostream>& log )
{
log_ = log;
}
};

Finally, you could use a (global) singleton log object. See chapter 6
of _Modern C++ Design_ for copious detail on how to implement such a
singleton to meet different needs. A simple version might look like:

template<class T>
class Singleton
{
public:
static T& Instance();
private:
// Disabled functions (no bodies provided)
Singleton();
Singleton( const Singleton& );
Singleton& operator=( const Singleton& );
Singleton* operator&();
~Singleton();
};

template<class T>
T& Singleton<T>::Instance()
{
static T myObject;
return myObject;
}

// Assume class Log is defined somewhere
typedef Singleton<Log> theLog;

class MyClass
{
public:
// ...
~MyClass() { theLog::Instance() << "MyClass destroyed."; }
};

Also, see these FAQs for why you shouldn't use arrays polymorphically:

http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.4
http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.5

Cheers! --M
 
A

Angel Tsankov

Angel Tsankov said:
I need to make verifications in release builds. If a verification
fails, an error message should be displayed and the program should
be
aborted. I need this solution to be portable. Then I thought of the
assert macro - it provides the desired functionality but only if
NDEBUG is not defined. So, I could write smth like this:

#if defined NDEBUG
#undef NDEBUG
#include <cassert>
#define NDEBUG
#else
#include <cassert>
#endif

Unfortunately, NDEBUG could be defined to something meaningful, in
which case it's value would be lost.

However, code that tests NDEBUG for specific values has undefined
behavior (doesn't it?) and should be avoided. Therefore, it should be
OK to use the #undef-#define trick with NDEBUG, right?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top