A balanced function is one of a pair of functions such that every call to the
first function must be balanced with exactly one call to the second function,
and vice versa, much like balancing brackets in an expression. There is often
some associated object to carry state between the calls.
The canonical examples are
free, with their
intermediate state represented by a pointer.
delete go one step further and balance a call to
plus a call to a constructor with a call to
free plus a call to
There are many examples throughout the standard library:
- the non-default non-copy constructor and
Other common names seen in the wild include (
stop) and (
For this post, I will follow a naming convention of
The best way to ensure balanced function calls in C++ is by using constructors and destructors. Constructors and destructors are themselves balanced functions that, much of the time, the language will balance for us. We can piggy-back on that automatic balancing to balance calls to other functions.
For objects without dynamic storage duration (i.e. with automatic, static, or thread storage duration), the language guarantees that every call to a constructor is balanced with a call to the corresponding destructor, even in the presence of exceptions. Transitively, an object that enjoys balanced constructor and destructor calls will correctly balance those calls for its base classes and non-static members.
Balancing constructors with destructors for objects with dynamic storage
duration is left as an exercise for the programmer, but the standard
containers and smart pointers correctly balance them for the objects they
By avoiding direct contact with dynamic storage duration, e.g. by never
delete, we can ensure that all the constructors
and destructors in our program are correctly balanced.
Where's the potential bug in this code?
b_->start() throws, then the
Application constructor will exit
a_ has started.
Because the constructor exited abnormally, the
Application destructor will
never be called, and thus the balancing call to
a_->stop() will never
It may be that
a_ is a member who is destroyed when the
constructor exits, but not all destructors can be expected to call the
balancing stop function. For example,
Rearranging the calls to
start cannot fix the bug: what if
If a destructor balances a start function called by a constructor, then the constructor must ensure it does not call any function that may throw an exception after it calls the start function. Generally, the easiest way to follow this rule is to call only one start function per constructor body, and to leave the call as the last statement in the body.
If we want to call multiple start functions from a single constructor, then they need to be called by constructors of members of that class. If one of those member constructors exits abnormally, the language guarantees that the balancing destructors for every member constructor that finished before it will be called.
Does this mean we must write a separate RAII type for every pair of balanced functions in our API? Yes! But it doesn't have to be "separate". Before adding start and stop methods to a type, I first see if I can move that behavior to the type's constructor and destructor instead, making the type itself follow RAII.
Often that's not an option. Perhaps the object can be started and stopped
multiple times, but it can only be constructed and destroyed once.
Or perhaps the start and stop functions are free functions, not methods.
My next preferred technique is to make my start function return a RAII object
that calls the stop function in its destructor.
The caller can manage the stop object's lifetime, thus choosing when its
destructor is called, while letting the language guarantee that it is called
To help callers use the API correctly,
the start function return type should be annotated
[[nodiscard]] and if the
stop function is a method, it should be private.
The stop object should be moveable but not copyable; a copy would call the
stop function more than once.
Finally, if that is not an option, then I follow the pattern of
std::lock_guard and add a new RAII type whose sole purpose is
to balance calls to start and stop functions using its constructor and
If you prefer the convenience of a single type, these last two techniques can be combined by having a public start method return a RAII type that calls a private start method in its constructor.
Every pair of balanced functions must have a corresponding RAII type that balances those functions using its constructor and destructor. If such a RAII type is missing, the API will be difficult to use correctly.