Terminology:
By the term ‘invariants’, it is meant relationships that must hold true regarding the state of a class, at the time that a public function is entered or exited.
By ‘state’ it is meant the combined values of its members.
By ‘members’ it is meant the “raw bits” of the class footprint.
Invariants-checks, as a debugging aid, may, but need not cover all possible invariants. Expensive checks are better avoided, as they will be invoked at every public function call.
Checks are only strictly necessary either at entry or at exit points of functions, not both. See under ‘Rationale’.
Invariants checks are not to be applied to private, protected or const functions; nor, of course, to static functions; and they are only compiled in debug mode.
Invariants must NOT themselves be thread-safe. More details on this below, under Thread Safety.
Description:
Abstract class ‘invariants’ imbues a derived class with a basic mechanism for invariant checking, via inheritance. Pure virtual function ‘void verify_invariants() const’ must be defined in the derived class.
Nested class invariants::trigobj is a class whose destructor triggers a call to invariants::verify_invariants(). It is to be instantiated as the first automatic variable in every non- -const public function of the derived class.
Rationale:
The call to verify invariants could be made at the entry and exit points of functions, but one of the two is sufficient, provided the class does not have evil friends. Checking only at exit was chosen as the policy in order to catch a bug within the function where the bug resides, rather than at the time of the next public function call. This choice, however, would make the placing of calls to check invariant more laborious and error-prone, as each function may have multiple return points. Ergo, the use of a trigger class to be instantiated first on the stack within each public, non- -const function.
Invariants should also be checked after initialization and before destruction. Functions ‘void first_verify() const’ and ‘void last_verify() const’ are provided for this purpose. The call to first_verify can be made from the bodies of ctors, but after any other state-modifying operations therein. The call to last_verify may be placed as the first statement within the bodies of destructors. A boolean member ‘enabled_’ is set to true by first_verify, and to false by last_verify. Calls to verify_invariants (triggered by the destructor of trigobj vars upon returning from non-const public functions) should occur while enabled_ is true, otherwise an internal assertion will stop execution. Other internal assertions include checks to ensure that enable_ isn’t set to true (or false) repeatedly.
Implementation Notes:
All member functions are no-throw, unless bad-alloc is thrown during construction, which everybody knows, so I skipped the no-throw comments.
The enable_ variable is a char to minimize size augmentation of the client class; and it is mutable so that first and last verify functions can be const, –so that they can be called from const functions in the derived class, if wished.
The copy constructor and assignment operators are immutable; –i.e.: They copy nothing at all, just ignore the operation, as the only data member, enabled_, must be initialized to false on construction, and can’t be allowed to be changed by anything but first_verify() and last_verify().
There is a reason why the assignment operator doesn’t invoke check_invariants(): If it did, it would be malformed, for the call would occur prior to assignment, as class invariants is the ancestor class, and therefore is assigned first. Thus, it would serve no purpose at best. The right and only way to post-check assignment is by instantiating trigobj within it, just the way normal functions are made invariant-checked.
Thread Safety:
Class invariants is not designed to be thread-safe, and should not be. The rationale is that if the derived class itself is thread-safe, so will class invariants within it. Otherwise, there are two possibilities: either the derived class does not need thread safety (as it may be in use within a single thread environment, or only called from within one thread; or else the derived class does need, but does not have, thread safety, due to programmer error. In this last case, class invariants will probably find the state of the object incoherent, at some point, which will alert the programmer to the situation. This last benefit would be lost if class invariants were, itself, thread-safe.
To be done:
I guess it could use a bit of MPL to apply invariant checks to compile-time objects...
Revision History
Version void – Jan 6, 2004 First draft. Version 1.00 – Jan 7, 2004:
- Used curiously recurring template< Derived > pattern and
provided dummy pointer to virtual function check_invariants in order to avoid name collisions in multiple inheritance.
- Added call to check_invariants in the ctor of trigobj, so
that invariants are checked on function entry, as well as on function exit. Thanks to Dave Gomboc.
- Cleaned up macros: Added function call syntax and semicolon
requirement idioms, and such.
- Replaced ENSURE macro for DMC workaround, to use int 3
explicitly instead of the assert macro from <cassert>.
- Updated documentation; e.g.: Added Revision History.. :)


