If I use assert() and the assertion fails then assert() will call abort(), ending the running program abruptly. I can't afford that in my production code. Is there a way to assert in runtime yet be able to catch failed assertions so I have the chance to handle them gracefully?
Yes, as a matter of fact there is. You will need to write a custom assert function yourself, as C++'s assert() is exactly C's assert(), with the abort() "feature" bundled in. Fortunately, this is surprisingly straightforward.
Assert.hh
template <typename X, typename A>
inline void Assert(A assertion)
{
if( !assertion ) throw X();
}
The above function will throw an exception if a predicate doesn't hold. You will then have the chance to catch the exception. If you don't catch the exception, terminate() will be called, which will end the program similarly to abort().
You may wonder what about optimizing away the assertion when we're building for production. In this case, you can define constants that will signify that you're building for production and then refer to the constant when you Assert().
debug.hh
#ifdef NDEBUG
const bool CHECK_WRONG = false;
#else
const bool CHECK_WRONG = true;
#endif
main.cc
#include<iostream>
struct Wrong { };
int main()
{
try {
Assert<Wrong>(!CHECK_WRONG || 2 + 2 == 5);
std::cout << "I can go to sleep now.\n";
}
catch( Wrong e ) {
std::cerr << "Someone is wrong on the internet!\n";
}
return 0;
}
If CHECK_WRONG is a constant then the call to Assert() will be compiled away in production, even if the assertion is not a constant expression. There is a slight disadvantage in that by referring to CHECK_WRONG we type a little more. But in exchange we gain an advantage in that we can classify various groups of assertions and enable and disable each of them as we see fit. So, for example we could define a group of assertions that we want enabled even in production code, and then define a group of assertions that we only want to see in development builds.
The Assert() function is equivalent to typing
if( !assertion ) throw X();
but it clearly indicates the intent of the programmer: make an assertion. Assertions are also easier to grep for with this approach, just like plain assert()s.
For more details on this technique see Bjarne Stroustrup's The C++ Programming Language 3e, section 24.3.7.2.
glib's error reporting functions take the approach of continuing after an assert. glib is the underlying platform independence library that Gnome (via GTK) uses. Here's a macro that checks a precondition and prints a stack trace if the precondition fails.
#define RETURN_IF_FAIL(expr) do { \
if (!(expr)) \
{ \
fprintf(stderr, \
"file %s: line %d (%s): precondition `%s' failed.", \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
#expr); \
print_stack_trace(2); \
return; \
}; } while(0)
#define RETURN_VAL_IF_FAIL(expr, val) do { \
if (!(expr)) \
{ \
fprintf(stderr, \
"file %s: line %d (%s): precondition `%s' failed.", \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
#expr); \
print_stack_trace(2); \
return val; \
}; } while(0)
Here's the function that prints the stack trace, written for an environment that uses the gnu toolchain (gcc):
void print_stack_trace(int fd)
{
void *array[256];
size_t size;
size = backtrace (array, 256);
backtrace_symbols_fd(array, size, fd);
}
This is how you'd use the macros:
char *doSomething(char *ptr)
{
RETURN_VAL_IF_FAIL(ptr != NULL, NULL); // same as assert(ptr != NULL), but returns NULL if it fails.
if( ptr != NULL ) // Necessary if you want to define the macro only for debug builds
{
...
}
return ptr;
}
void doSomethingElse(char *ptr)
{
RETURN_IF_FAIL(ptr != NULL);
}
Asserts in C/C++ only run in debug builds. So this won't happen at runtime. In general asserts should mark things that if they happen indicate a bug, and generally show assumptions in your code etc.
If you want to have code that checks for errors at runtime (in release) you should probably use exceptions rather than asserts as these are what they are designed to do. Your answer basically wraps an exception thrower in assert syntax. While this will work, there is no particular advantage to this that I can see over just throwing the exception in the first place.
Here's what I have my in "assert.h" (Mac OS 10.4):
#define assert(e) ((void) ((e) ? 0 : __assert (#e, __FILE__, __LINE__)))
#define __assert(e, file, line) ((void)printf ("%s:%u: failed assertion `%s'\n", file, line, e), abort(), 0)
Based on that, replace the call to abort() by a throw( exception ). And instead of printf you can format the string into the exception's error message. In the end, you get something like this:
#define assert(e) ((void) ((e) ? 0 : my_assert (#e, __FILE__, __LINE__)))
#define my_assert( e, file, line ) ( throw std::runtime_error(\
std::string(file:)+boost::lexical_cast<std::string>(line)+": failed assertion "+e))
I haven't tried to compile it, but you get the meaning.
Note: you'll need to make sure that the "exception" header is always included, as well as boost's (if you decide to use it for formatting the error message). But you can also make "my_assert" a function and only declare its prototype. Something like:
void my_assert( const char* e, const char* file, int line);
And implement it somewhere where you can freely include all the headers you require.
Wrap it in some #ifdef DEBUG if you need it, or not if you always want to run those checks.
If you want to throw a character string with information about the assertion:
http://xll8.codeplex.com/SourceControl/latest#xll/ensure.h
_set_error_mode(_OUT_TO_MSGBOX);
believe me, this function can help you.
Related
I am trying to write my own custom assert for my own project. This project will be written with c++11.
The assert must have the following qualities:
It must be kept as an expression and is assignable.
E.g. I should be able to write code like this int x = custom_assert(1/y);
It must be overloaded to accept an assert with a message and without one.
E.g int x = custom_assert(1/y, "Error divide by zero"); This code and the above are both compilable and acceptable.
It must have no side-effects in release mode
E.g. int x = custom_assert(1/y); will become int x = 1/y; in release mode.
And most importantly, it must break at the specific point where the assert was made. Which will make use of __debugbreak() as part of its evaluating expression.
The following is my attempt:
#include <string>
bool DoLog(std::string msg, std::string file, int line); //Prints to std::cerr and returns HALT macro
#if defined(_DEBUG) || defined(DEBUG)
#define HALT true
#define NT_ASSERT_BASE(x, msg) (!(x) && DoLog((msg), __FILE__, __LINE__) && (__debugbreak(),1))
#else
#define HALT false
#define NT_ASSERT_BASE(x,msg) (x)
#endif//debug/release defines
//--- Can't implement these until I can return the expression ---
//#define GET_MACRO(_1,_2,_3,NAME,...) NAME
//#define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__)
#define NT_ASSERT(expression, msg) NT_ASSERT_BASE(expression,msg)
As you can see my custom assert fails on 2 fronts, namely being kept as expression and assignable, and on overloading (Which I cannot implement until I figure out how to keep it as an expression.
All in all, I may be chasing stars and this macro may in fact be impossible to make. (Which I hope isn't the case)
Many thanks.
As far as I can tell, this can't be done in standard C++.
There is no way to get the __debugbreak() into the expanded code and at the same time pass the result of the expression unmodified, because you need the result twice: once for testing it, which will implicitly cast it to bool, and once to return it at the end.
There are two options:
Use gcc's and clang's ({}) construct with auto variable to hold the result. That will exclude MSC++, but I suppose you want that, because __debugbreak() is a MSC++ misfeature.
Give up on requiring the __debugbreak() on the call site, accept having to go one level up when it stops and make the thing as a template function.
A lambda expression will fit slightly better than a template function. It will make the break appear at the macro site, but it will still appear as a separate stack frame in the call stack. It also requires C++11 support (it was published over 5 years ago, but some platforms may not have it).
I don't think you should be mixing the validation with the assignment. From your example, it looks like you want to assign to an integer but an assertion, by nature, is a boolean expression. Further, your example is asserting on the wrong expression. It looks like you want to assert that y is not equal to zero (preventing division by zero), but you are asserting against something that will also be one or false or undefined.
If you are willing to be a bit flexible with your assignment requirements, then we can work around the problem of maintaining the expression and other useful info with some macro magic. Further, we can execute the __debugbreak() at the call site.
#include <iostream>
#include <string>
#include <type_traits>
template<class Fun>
inline bool DoLog(Fun f, std::string message, const char *expression, const char *filename, int line) {
static_assert(std::is_same<bool, decltype(f())>::value, "Predicate must return a bool.");
if (!(f())) {
std::cerr << filename << '#' << line << ": '" << expression << "' is false.";
if (!message.empty()) {
std::cerr << ' ' << message;
}
std::cerr << std::endl;
return false;
}
return true;
}
#if defined(_DEBUG) || defined(DEBUG)
#define HALT true
#define WITH_MESSAGE_(expr, x) [&](){return (expr);}, x, #expr
#define WITHOUT_MESSAGE_(expr) [&](){return (expr);}, std::string{}, #expr
#define PICK_ASSERTION_ARGS_(_1, _2, WHICH_, ...) WHICH_
#define CREATE_ASSERTION_ARGS_(...) PICK_ASSERTION_ARGS_(__VA_ARGS__, WITH_MESSAGE_, WITHOUT_MESSAGE_)(__VA_ARGS__)
#define NT_ASSERT(...) if (!DoLog(CREATE_ASSERTION_ARGS_(__VA_ARGS__), __FILE__, __LINE__)) __debugbreak()
#else
#define HALT false
#define NT_ASSERT(...)
#endif
int main() {
NT_ASSERT(true);
NT_ASSERT(false);
NT_ASSERT(1 == 1, "1 is 1");
NT_ASSERT(1 == 0, "1 is not 0");
return 0;
}
NOTE: The above snippet works on GCC using -std=c++11 (with a placeholder for the __debugbreak() statement). I'm making an assumption that VC++ would work also when it fully supports C++11.
Is it possible to replace this preprocessor macro:
#define AL_CALL(a) do { a; \
ALenum e = alGetError(); \
if(e != AL_NO_ERROR) \
UtilitySoundNode::printALError(e,__FILE__, __LINE__); \
} while(0)
with a C++ template? If it is possible, will make any sense to do it (pros/cons - overhead/debugging)?
Note:
Basically I am wondering if there is an elegant way to handle this kind of error handling in C++.
EDIT:
Of course I made a mistake a is a function call. As one may guess it is a function call with parameters of a OpenAL function.
AL_CALL(someAlFunction(param1, param2))
NOTE:
Somebody decided to edit the macro and make it nicer but I'd prefer to keep the original one too. So here it is:
#define AL_CALL(a) {a; ALenum e = alGetError();if(e != AL_NO_ERROR)PUtilitySoundNode::printALError(e,__FILE__, __LINE__);}
One problem here seems to be that the "a" can be some arbitrary function (with parameters) which sets the error code returned by alGetError().
That can be rewritten to C++ by using a functor object. To pass the arguments (and object instance if necessary) std::bind or boost::bind can be used (note that to bind reference args the std::ref/boost::ref is necessary).
However, if you'd want to still have the __FILE__ and __LINE__ passed the the printError() that C++ template still would need to be called by a macro which will pass those to the template. __FILE__ and __LINE__ are only expanded by the preprocessor, so there is no way around using a macro for them.
But the macro could be much simpler then and most of the work can be done in the C++ template (which has many advantages e.g. for debugging, because in most debuggers you cannot step into a macro).
EDIT: adding the code as an example:
template<typename T>
void ALcallAndCheck(T c, const char *file, size_t line)
{
c();
ALenum e = alGetError();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e, file, line); \
}
#define AL_CALL(a) ALcallAndCheck(a, __FILE__, __LINE__)
Then, instead of
AL_CALL(SomeFunction(2, refAttr));
the call will become:
AL_CALL(std::bind(SomeFunction, 2, std::ref(refAttr)));
EDIT 2:
The previous indeed does not work with expressions, which the original macro allows. To work also for expressions, the macro can be altered to:
#define AL_CALL(a) ALcallAndCheck([&]{ (a); }, __FILE__, __LINE__)
That will create a lambda which will evaluate anything that comes into the macro. Then even the std::bind is not necessary and it can be called directly as:
AL_CALL(SomeFunction(2, refAttr));
AL_CALL(SomeOtherFunction1()+SomeOtherFunction2(8));
No, the use of __FILE__ and __LINE__ pretty well require the preprocessor.
Note that using a template instead of a macro does not produce an exact analog. The macro defined in your question allows a to represent a statement as well as an expression. A template does not have that kind of flexibility. The template defined below assumes a is a non-void expression.
There is no standard way to implicitly inject a function caller's file name and line number without the caller passing in that information to the called function. A preprocessor macro allows a means to make the syntax appear to be implicit injection, when in fact the information is being passed.
template <typename T>
void AL_CALL (T a, const char *file, int line) {
ALenum e = alGetError();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e, file, line);
}
#define AL_CALL(X) AL_CALL((X), __FILE__, __LINE__)
You may be able to use system specific facilities (e.g., CaptureStackBackTrace + SymFromAddr or backtrace + backtrace_symbols) to get approximately the same information implicitly, but it may require debugging symbols to be present, and inline functions may not produce the expected output.
template<class A>
void al_call(A&&a){
ALenum e = a();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e,__FILE__, __LINE__);
}
Use:
al_call( [&]{ return bob(); });
Instead of:
AL_CALL( bob() )
The line/file info is not useful above.
So
template<class A>
void al_call(A&&a, char const*file, unsigned line){
ALenum e = a();
if(e != AL_NO_ERROR)
UtilitySoundNode::printALError(e,file, line);
}
#define AL_CALL(...) al_call([&]()mutable{return __VA_ARGS__;}, __FILE__, __LINE__)
and it is almost a drop in replacement.
This question already has answers here:
How to put assert into release builds in C/C++
(7 answers)
Closed 1 year ago.
Where can I find an ASSERT similar to the assert(...) macro from the standard C++ library (the one defined in <cassert>), but that works on Release mode too? Or how should I write one?
I like assert(...) because it automatically prints the line my source file where the assertion failed, as well as the assertion expression. I expect those features (if possible) in the Release mode ASSERT as well.
Basically assert is a macro that evaluates the expression and if it fails prints something and then aborts. It's not that hard to write something similar, something like.
#define ASSERT(x) do { if( !(x) ) { printfunc( #x ); abort(); } while(0)
Then you can modify that in order to suit your requirements. For example you might want not to abort in release mode. You could also adjust your printouts (to include just the information that you think is useful), in order to get file and line information you would use __FILE__ and __LINE__ macros (btw the #x in the define expands to a string literal containing the expression x).
In your release build, don't define NDEBUG, and assert will work.
You can undefine NDEBUG
#undef NDEBUG
near the assert statement
or you can define your own assert
#define assert(x) printf(...)
I've rolled out my own assertions that always fire in release mode too, based on this article:
This is the GIST of it, with me not providing the actual implementation (of AbstractAsserter, which is based on the article), but you get the idea:
#include <iostream>
struct AbstractAsserter
{
virtual void doAssert(const char* expr, const char* file, int line, const char* function) const
{
std::cout << "Asserting now at " << expr << ", " << file << ", " << line << ", " << function << std::endl;
}
};
struct Local
{
const char* function_;
const char* expr_;
const char* file_;
int line_;
Local( const char* f, const char* ex, const char* file, int line )
: function_( f ), expr_( ex ), file_( file ), line_( line )
{ }
Local operator << ( const AbstractAsserter& impl )
{
impl.doAssert( expr_, file_, line_, function_ );
return *this;
}
};
// More to be added as required...
#if defined( __GNUC__ )
# define WE_FUNCTION __PRETTY_FUNCTION__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
# define WE_FUNCTION __func__
#else
# define WE_FUNCTION "null_func()"
#endif
#define WE_ASSERT( expr )\
if( expr );\
else Local( WE_FUNCTION, #expr, __FILE__, __LINE__ )\
<< AbstractAsserter();
int main() {
WE_ASSERT(!"bad BAD BOY!");
return 0;
}
With this structure, your implementation may also do some critical saving of state etc (if you deem your program state trustworthy...debatable).
Using the std assert in release mode (where, by the comments, you would like compiler optimizations enabled), isn't a problem per se, as is established by the other answers. Writing a custom one has been done, so there's not much problem there.
However, to quote the Dr. Dobb's article:
Do use assertions liberally throughout your code; they are watchful, reliable guards that protect you (your program) from insanity
If you are worried to have assertion + compiler optimizations, then these two thing are a bit add odds conceptually:
Asserts should and can be used liberally, with the intention of finding bugs early, and mostly so that it doesn't matter whether the assert code hurts performance.
If you want/need to run with optimizations, you may not like the performance hit the additional (now optimized, but still) assert code gives you.
So, in summary, I see the use of a relase mode assert, but make sure to keep it separate from the "normal" assert, where most people would assume it to be off in release mode.
I would like to create a custom version of the assert macro defined in <cassert>, that displays an error message when the assertion fails.
Desired usage:
custom_assert(AClass<T1, T2>::aBoolMethod(), "aBoolMethod must be true");
Flawed test implementations:
#define custom_assert(mCondition, mMessage) ...
// This fails because mCondition may have commas in it
#define custom_assert(..., mMessage)
// Not sure about this either - mMessage may be an expression containing commas
// as well
How can I correctly implement a custom assert that takes a boolean expression (with possible commas) as the first argument and a string expression (with possible commas) as the second argument?
Or is there a way to implement assertions without the use of macros?
You were quite close, what you need to use is simply this:
#define myAssert(message, ...) do { \
if(!(__VA_ARGS__)) { \
/*error code*/ \
} \
} while(0)
The special preprocessor variable __VA_ARGS__ will expand to whatever was passed in the place of the three dots, including all comas.
Note that the preprocessor will not interprete commas in the condition in the very least, it will just paste them as is into the if() statement. Which is precisely what you want if you want to pass templated conditions, as hinted by the comments.
Commas in the message string are not a problem either, since the preprocessor understands about string literals and does not interprete anything within the double quotes.
The straightforward
assert(AClass<T1, T2>::aBoolMethod() && "aBoolMethod must be true");
fails:
error: macro "assert" passed 2 arguments, but takes just 1
but if you add an extra pair of parenthesis around the first argument, it works. Like this:
#include <cassert>
template <typename A, typename B>
struct C {
bool f() { return false; }
};
int main() {
assert((C<int,int>().f()) && "some message, with comma");
// ^ ^
}
Note: it was also pointed out by Adam Rosenfield in a comment.
Perhaps the only benefit over the __VA_ARGS__ approach is that it doesn't dump yet another macro on the user. If you forget the parenthesis, you can get a compile time error, so I see it as a safe solution.
For the sake of completeness, I published a drop-in 2 files assert macro implementation in C++:
#include <pempek_assert.h>
int main()
{
float min = 0.0f;
float max = 1.0f;
float v = 2.0f;
PEMPEK_ASSERT(v > min && v < max,
"invalid value: %f, must be between %f and %f", v, min, max);
return 0;
}
Will prompt you with:
Assertion 'v > min && v < max' failed (DEBUG)
in file e.cpp, line 8
function: int main()
with message: invalid value: 2.000000, must be between 0.000000 and 1.000000
Press (I)gnore / Ignore (F)orever / Ignore (A)ll / (D)ebug / A(b)ort:
Where
(I)gnore: ignore the current assertion
Ignore (F)orever: remember the file and line where the assertion fired and
ignore it for the remaining execution of the program
Ignore (A)ll: ignore all remaining assertions (all files and lines)
(D)ebug: break into the debugger if attached, otherwise abort() (on Windows,
the system will prompt the user to attach a debugger)
A(b)ort: call abort() immediately
You can find out more about it there:
blog post
GitHub project
Hope that helps.
I'm not entirely sure what you mean by a "boolean expression with commas." Simply wrapping macro expansions in commas (as seen in the samples below) protects against parse errors if you happen to use the default comma operator in your conditions, but the default comma operator does not do the same thing as &&. If you mean you want something like:
my_assert(condition1, condition2, message1, message2);
You're out of luck. How should any API tell where the conditions stop and the messages start. Just use &&. You can use the same tricks below for handling the message portion to also create a my_condition_set macro that allows you to write something like:
my_asssert(my_condition_set(condition1, condition2), message1, message2);
Getting to the message part, which is the tricky part and the most useful part that the standard assert macros tend to lack, the trick will come down to either using a custom message output type that overrides operator, (the comma operator) or to use a variadic template.
The macro uses variadic macro support and some tricks to deal with commas. Note that none of the code I'm posting here is tested directly; it's all from memory from custom assert macros I've written in the past.
The version using comma operator overloading, which works in C++98 compilers:
struct logger {
template <typename T>
logger& operator,(const T& value) {
std::cerr << value;
return *this;
}
};
#define my_assert(condition, ...) do{ \
if (!(condition)) { \
(logger() , __VA_ARGS__); \
std::terminate(); \
} \
}while(false)
The logger() expression creates a new instance of the logger type. The list of arguments from __VA_ARGS__ is then pasted with commas separating each. These commas each invoke the comma operator left-to-right, which forwards the expression on to std::cerr. I usually use a custom log stream that handles writing to files, cerr, Windows' OutputDebugStringA, or whatever.
Using variadic templates in a C++11 compiler, this would be more like:
template <typename ...Ts>
void logger(Ts&&... argv) {
std::cerr << your_string_format_function(argv...);
}
void logger(const char* fmt) {
std::cerr << fmt;
}
void logger() {}
#define my_assert(condition, ...) do{ \
if (!(condition)) { \
logger(__VA_ARGS__); \
std::terminate(); \
} \
}while(false)
You'd need a format string function that actually works with variadic arguments or write an adapter for something like boost::format.
You could also use printf if you don't mind the lack of type-safety.
Today I discovered some of my assertion functions are still exist and being called in release build. Here's an example of my assertion function.
bool const isDebugMode()
{
return false; // Will be controlled by preprocessor flag.
}
void assertWithReason(bool const condition, std::string const reason = "")
{
if (isDebugMode() and not condition)
{
abort();
}
}
I think some side-effect in condition expression is preventing eliminating the assertion call.
For example,
assertWithReason(glGetError() == GL_NO_ERROR);
I expected this assertion call to be eliminated, but it is not. Because it is being executed before checking debug-build.
I am not sure how C++ handles this case, but as C++ is very strict language, it doesn't seem to be eliminated unless I put some special flag. Anyway, I intentionally wrote the assertions to be removed in release build.
Is it possible to write a function which is surely removed in release build in C++?
Of course I can use preprocessor macro, but I want to avoid using preprocessor macro as much as possible.
I am using Clang, and compiler specific extension (such as GCC attribute) is also fine.
I quite like using macros for this purpose. Yes, I know, Macros are evil, but just like knives (used wrong) are evil, they come in handy if you use them right.
#define MY_ASSERT(x) do {\
if (is_debug() && !x) assertFailed(__FILE__, __LINE__, __FUNCTION__, #x);\
} while(0);
Now you can also show where it failed (my_drawfunc.cpp: 34 : my_do_draw(): assertion failed: glGetError == GL_NO_ERROR or something like that.
In C++11 you can use lambda expressions. It is likely that constant propogation will make it so that is_debug is never evaulated, and even if it is, the lambda is not called.
class Debug { enum { is_debug = 1; } };
template <class F>
void assert(F f) {
if (is_debug && !f()) abort();
}
{
int x = 6;
assert([&]() { return x == 6; });
}