There are a few ways to keep certain assert()
calls active in release builds:
Option 1: Rather than defining the global NDEBUG
macro disable assert()
calls, we can implement our own conventions. For example, we could use #ifdef
 directives with macros that have names like ENABLE_ASSERTIONS
and ENABLE_RELEASE_ASSERTIONS
:
#include <cassert>
int Divide(int x, int y) {
#ifdef ENABLE_RELEASE_ASSERTIONS
assert(y != 0 && "Cannot divide by zero");
#endif
return x / y;
}
We then have more granular control over which assertions are enabled, based on which definitions we provide in our project settings
Option 2: Create a custom assert-like macro that isn't disabled in release builds. In the following example, our RELEASE_ASSERT()
macro will be used whether or not NDEBUG
is defined:
#include <iostream>
#define RELEASE_ASSERT(expr) \
if (!(expr)) { \
std::cerr << "Assertion failed: " #expr; \
abort(); \
}
int Divide(int x, int y) {
RELEASE_ASSERT(y != 0);
return x / y;
}
int main() {
Divide(2, 0);
}
Assertion failed: y != 0
Option 3: Use logging libraries like spdlog or Boost.Log that offer assertion-like checks which remain enabled in release builds by default.
In general, the decision to keep assertions enabled in release builds is a tradeoff between performance and catching/logging critical errors. Enable them selectively for the most crucial checks.
Answers to questions are automatically generated and may not have been reviewed.
Learn how we can ensure that our application is in a valid state using compile-time and run-time assertions.