Expressive assertion failure messages in C++

2019-08-15 10:40发布

问题:

Unit test frameworks generally provide very nice assertion failure messages (I'm using gtest) describing expected and actual values to a particular test. Furthermore, you know the origin of the function call because you're testing the interface of the class.

In contrast, assert, when used as a sanity check in the implementation provides some, but more cryptic information. For example, the one I'm working on now . .

Assertion failed: (latency > std::chrono::milliseconds(0)), function setLatency, file /path/to/my.cpp line 71

So I know which assertion failed, but I have no idea what the values were that caused it to fail, and more importantly, I don't know the problematic function from which setLatency was called.

A simple solution normally would be drop to the debugger, but I cannot do this in this instance. Is it possible to get a more descriptive assertion message from within the implementation of a class? How can I do this? I don't mind using a 3rd party lib if necessary.

回答1:

A common solution for this problem is to create an assert macro. For an example see this question. The final form of their macro in that answer was the following:

#define dbgassert(EX,...) \
  (void)((EX) || (realdbgassert (#EX, __FILE__, __LINE__, ## __VA_ARGS__),0))

In your case, the realdbgassert would be a function that prints any relevant information to stderr or other output console, and then calls the assert function itself. Depending on how much information you want, you could also do a stack dump, or log any other relevant information that will help you identify the issue. However, it can be as simple as passing a printf-esque format string, and relevant parameter value(s).

Note that if you compiler doesn't support variadic macros, you can create macros that take a specific number of parameters instead. This is slightly more cumbersome, but an option if your compiler lacks the support, eg:

#define dbgassert0(EX) \ ...
#define dbgassert1(EX,p0) \ ...
#define dbgassert2(EX,p0,p1) \ ...


回答2:

I am not sure if this is what you are looking for, but you can append any message you like to the "Assertion failed:.." message by doing something like this:

assert(1==1 && "This is always true");
assert(1==0 && "This always fails");

Of course you can modify the string to contain values or more information.