In computer programming an assertion is a predicate placed in a program to indicate that the developer thinks that the predicate is always true at that place. For example:
x > 8 always evaluates to
x > 8 is a predicate that will evaluate the condition and return either
Ok, so now why do we want to assert?
Many assertion implementations will also halt the program’s execution — this is useful, since if the program continued to run after an assertion violation occurred it might corrupt its state and make the cause of the problem more difficult to locate. Using the information provided by the assertion failure (such as the location of the failure and perhaps a stack trace, or even the full program state if the environment supports core dumps or if the program is running in a debugger), the programmer can usually fix the problem. Thus assertions provide a very powerful tool in debugging.
Programmers can use assertions to specify or enforce the pre-conditions and post-conditions of states under which the programmer expects the code to execute. This is very useful while developing application/code as it helps to find out defects/bugs before the application is shipped.
This was about runtime assertion, where the predicate is evaluated based on the runtime state of application. What about library developers that want to ensure that their libraries are used with correct type?
Well, library developers can write out the boilerplate code for each type that they expect and ship out the code, this way they can ensure there are no surprises. But for supporting new types, new APIs will have to be added. This can become big pain. Second option is to use C++ Templates, write once use everywhere. This everywhere can soon be quite painful. With templates the function/class will be generated for the specified type, even if you don’t want them to be generated.
For example: I have my own class hierarchy and have smart pointers that do memory management from a managed memory region. The memory is allocated and deallocated from this region only for types in my hierarchy, so how do I constrain the creation of smart pointers so that any other class out of hierarchy will not work with my smart pointers, rather than corrupt memory at runtime.
There are several ways: - Document and blame users if they screw up - Enforce requirement during code-reviews (works internally only) - Fail compilation of such code
First two options are difficult to practice, third seems to be an interesting choice. Ok, so here is my class hierarchy:
And here is my implementation of SmartPointer, this works with classes deriving from A only.
With these implementations in place, I can write code like this and it compiles and links, but it will corrupt memory at run time.
The problem is templates are used as code generation mechanism but constraints are missing for types and that’s where
static_assert comes into picture.
So if I add one more line to my SmartPointer class to enforce hierarchical constraint.
With this definition in place, above code fails to compile with error message:
One more application of
static_assert can be to create stack allocated array of elements. This is very similar to creating stack allocated array of several elements. But we want to constrain how much memory this array can consume. Stack, typically, has 1 MB memory to start with and can have max of 2MB. Stack memory is very fast and very premium for high performance softwares.
constant_expression is an integral constant that can be converted to boolean and
string_literal is some sensible message to be displayed when
constant_expression evaluates to
In our case:
static_assert(::boost::is_base_of<A, T>::value, "The parametric type must derive from A");
::boost::is_base_of<A, T>::value. It’s one of the type_traits available in boost library.
is_base_of<A,T>::value evaluates to
true only if the
T publicly derives from
Well this is just one of the scenarios where
static_assert can be used.
static_assert can be helpful to convert runtime time errors to compilation errors.
I hope this post will prove useful for readers to get started with this C++11 feature.