I
Immortal Nephi
You can write your own assert macro. I have seen that assert macro
always use either abort() or terminate(). abort() causes serious
problems if it does not call class’ destructor to deallocate memory.
Memory leak is getting worse and the performance is dropped from the
operating system while you call abort() many times.
Exception handler is the best option over abort(). You can write
your own message box in either windows or console.
I write Error_Report class. Error_Report class is different from
exception class because it does not require inheritance. All the data
members and member functions of Error_Report have static storage.
Static storage is required. If you do not declare static, then after
throw is invoked, throw calls Error_Report’s constructor and
destructor before both data members pop out of stack and going to the
catch block.
You can add error messages to the enum block. You use assert macro
to select error message.
I have seen many arguments against placing exception in assert.
My code looks very clear. You can always customize message box, but
assert macro is not changed.
#include <iostream>
#include <string>
#include <sstream>
class Error_Report {
public:
enum Code {
OUT_OF_RANGE,
POINTER_NULL,
NORMAL
};
enum Behavior {
e_ABORT,
e_RETRY,
e_IGNORE,
};
Error_Report( Code _code ) {
code = _code;
}
~Error_Report() {
}
static char* What() {
return Error_Report::message[ code ];
}
static Behavior Assert(
Code _code,
const char* File,
const int LineNumber,
const char* Function ) {
std:stringstream text;
text << "Debug Assertion Failed!\n\nFile: " << File <<
"\nLine: " << LineNumber << "\nFunction: " << Function <<
"\n\nExpression: " << message[ _code ] <<
"\n\nFor information on how your program can cause a report\n" <<
"failure, see the Visual C++ documentation on asserts.\n\n";
std::string prompt;
bool condition = true;
std::cerr << text.str(); // you can use MessageBox instead
while( condition ) {
std::cerr << "(Press 'A' key to abort or press 'I' to ignore)\n" <<
"(Press 'R' key to debug the application)\n"
"Prompt: ";
std::ws( std::cin );
std::getline( std::cin, prompt );
if( prompt == "A" || prompt == "a" )
// abort();
throw Error_Report( _code );
else if( prompt == "R" || prompt == "r" )
return e_RETRY;
else if( prompt == "I" || prompt == "i" )
return e_IGNORE;
std::cerr << "\n\nInvalid input. Try again.\n";
}
return e_IGNORE; // not used here
}
private:
static Code code;
static char* message[ 3 ];
};
Error_Report::Code Error_Report::code = Error_Report::NORMAL;
char* Error_Report::message[ 3 ] = {
"Out of range",
"pointer null",
"Normal"
};
#define ASSERT( Expression, Message ) \
if( !( Expression ) ) { \
if( Error_Report::e_RETRY == Error_Report::Assert( \
Message, \
__FILE__, \
__LINE__, \
__FUNCTION__ ) ) \
__debugbreak(); \
}
int main() {
try {
int x = 5;
ASSERT( x < 4, Error_Report::OUT_OF_RANGE );
}
catch ( Error_Report &e ) {
std::cerr << "Error_Report: " << e.What() << endl;
}
return 0;
}
always use either abort() or terminate(). abort() causes serious
problems if it does not call class’ destructor to deallocate memory.
Memory leak is getting worse and the performance is dropped from the
operating system while you call abort() many times.
Exception handler is the best option over abort(). You can write
your own message box in either windows or console.
I write Error_Report class. Error_Report class is different from
exception class because it does not require inheritance. All the data
members and member functions of Error_Report have static storage.
Static storage is required. If you do not declare static, then after
throw is invoked, throw calls Error_Report’s constructor and
destructor before both data members pop out of stack and going to the
catch block.
You can add error messages to the enum block. You use assert macro
to select error message.
I have seen many arguments against placing exception in assert.
My code looks very clear. You can always customize message box, but
assert macro is not changed.
#include <iostream>
#include <string>
#include <sstream>
class Error_Report {
public:
enum Code {
OUT_OF_RANGE,
POINTER_NULL,
NORMAL
};
enum Behavior {
e_ABORT,
e_RETRY,
e_IGNORE,
};
Error_Report( Code _code ) {
code = _code;
}
~Error_Report() {
}
static char* What() {
return Error_Report::message[ code ];
}
static Behavior Assert(
Code _code,
const char* File,
const int LineNumber,
const char* Function ) {
std:stringstream text;
text << "Debug Assertion Failed!\n\nFile: " << File <<
"\nLine: " << LineNumber << "\nFunction: " << Function <<
"\n\nExpression: " << message[ _code ] <<
"\n\nFor information on how your program can cause a report\n" <<
"failure, see the Visual C++ documentation on asserts.\n\n";
std::string prompt;
bool condition = true;
std::cerr << text.str(); // you can use MessageBox instead
while( condition ) {
std::cerr << "(Press 'A' key to abort or press 'I' to ignore)\n" <<
"(Press 'R' key to debug the application)\n"
"Prompt: ";
std::ws( std::cin );
std::getline( std::cin, prompt );
if( prompt == "A" || prompt == "a" )
// abort();
throw Error_Report( _code );
else if( prompt == "R" || prompt == "r" )
return e_RETRY;
else if( prompt == "I" || prompt == "i" )
return e_IGNORE;
std::cerr << "\n\nInvalid input. Try again.\n";
}
return e_IGNORE; // not used here
}
private:
static Code code;
static char* message[ 3 ];
};
Error_Report::Code Error_Report::code = Error_Report::NORMAL;
char* Error_Report::message[ 3 ] = {
"Out of range",
"pointer null",
"Normal"
};
#define ASSERT( Expression, Message ) \
if( !( Expression ) ) { \
if( Error_Report::e_RETRY == Error_Report::Assert( \
Message, \
__FILE__, \
__LINE__, \
__FUNCTION__ ) ) \
__debugbreak(); \
}
int main() {
try {
int x = 5;
ASSERT( x < 4, Error_Report::OUT_OF_RANGE );
}
catch ( Error_Report &e ) {
std::cerr << "Error_Report: " << e.What() << endl;
}
return 0;
}