mirror of
https://github.com/boostorg/contract.git
synced 2026-01-26 06:22:42 +00:00
637 lines
50 KiB
Plaintext
637 lines
50 KiB
Plaintext
|
|
[section Tutorial]
|
|
|
|
This section illustrates basic uses of this library.
|
|
|
|
[section Non-Member Functions]
|
|
|
|
Consider the following non-member function `inc` which increments its argument `x` by `1` and returns the value `x` had before the increment (this function is equivalent to the usual C++ operation `x++`).
|
|
Let's write contracts for `inc` using code comments (see also [@../../example/features/function_comments.cpp =function_comments.cpp=]):
|
|
|
|
[import ../example/features/function_comments.cpp]
|
|
[no_contracts]
|
|
|
|
The precondition states that the argument to increment must be strictly smaller than the maximum allowable value of its type (to avoid overflow).
|
|
The postconditions state that the argument was actually incremented by `1` and that the function return value is equal to the argument before it was incremented.
|
|
|
|
Now let's program this function and its contract using the [funcref boost::contract::function] function from this library (see also [@../../example/features/function.cpp =function.cpp=]):
|
|
|
|
[import ../example/features/function.cpp]
|
|
[function]
|
|
|
|
All necessary header files of this library are included by `#include <boost/contract.hpp>`.
|
|
Alternatively, programmers can selectively include only the header files they actually need among =boost/contract/*.hpp= (see __Getting_Started__).
|
|
|
|
It is possible to specify both preconditions and postconditions for non-member functions (see __Preconditions__ and __Postconditions__).
|
|
|
|
The [funcref boost::contract::function] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::guard] otherwise the library will generate a run-time error (note that C++11 `auto` declarations cannot be used here and the [classref boost::contract::guard] type must be explicitly specified).
|
|
[footnote
|
|
The name of this local variable is arbitrary, but `c` is often used in this documentation.
|
|
]
|
|
The function body is programmed right after the declaration of this RAII object.
|
|
|
|
[note
|
|
In some cases, it might be necessary to program some code before the contract.
|
|
For example for acquiring resources that will be used while checking the contract like old values, but also to lock mutexes (or other synchronization mechanisms) in multi-threaded programs (as usual with C++, in these cases it is generally preferred to use RAII objects to automatically control acquisition and release of the resources).
|
|
]
|
|
|
|
At construction, the RAII object returned by [funcref boost::contract::function] does the following:
|
|
|
|
# Check preconditions, by calling the nullary functor [^['f]]`()` passed to `.precondition(`[^['f]]`)`.
|
|
|
|
At destruction instead:
|
|
|
|
# If the function body did not throw an exception:
|
|
# Check postconditions, by calling the nullary functor [^['g]]`()` passed to `.postcondition(`[^['g]]`)`.
|
|
|
|
This ensures that non-member function contracts are correctly checked at run-time (see __Function_Calls__).
|
|
|
|
[note
|
|
A non-member function can avoid calling [funcref boost::contract::function] for efficiency but only when it has no preconditions and no postconditions.
|
|
]
|
|
|
|
The same considerations also apply to private and protected member functions because their contracts are also programmed using [funcref boost::contract::function] like for non-member functions (see __Private_and_Protected_Functions__).
|
|
|
|
[endsect]
|
|
|
|
[section Preconditions]
|
|
|
|
When preconditions are specified, they are programmed using a functor that can be called with no parameter [^['f]]`()` and it is passed to `.precondition(`[^['f]]`)`.
|
|
Contracts that do not have preconditions simply do not call `.precondition(...)`.
|
|
When both preconditions and postconditions are specified, preconditions must appear before postconditions (see __Postconditions__).
|
|
|
|
C++11 lambda functions are very convenient to program preconditions, but any other nullary functor can be used (see also __No_Lambda_Functions__).
|
|
[footnote
|
|
Lambda functions with no parameters can be programmed in C++11 as `[...] () { ... }` but also equivalently as `[...] { ... }`.
|
|
This second from is often used in this documentation omitting the empty parameter list `()` for brevity.
|
|
]
|
|
For example, for [funcref boost::contract::function] (but same for all other contracts):
|
|
|
|
boost::contract::guard c = boost::contract::function() // Same for all other contracts.
|
|
.precondition([&] { // Capture by reference or value...
|
|
BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures.
|
|
...
|
|
})
|
|
...
|
|
;
|
|
|
|
The precondition functor should capture all the variables that it needs to assert the preconditions.
|
|
These variables can be captured by value when the overhead of copying such variables is acceptable (but in this documentation preconditions often capture these variables by reference to avoid such overhead).
|
|
In any case, precondition assertions should not modify the value of the captured variables, even when those are captured by reference (see __Constant_Correctness__).
|
|
|
|
Any code can be programmed for the precondition functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex preconditions that might be buggy and slow to execute at run-time).
|
|
It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program precondition assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, see also __No_Macros__):
|
|
|
|
BOOST_CONTRACT_ASSERT(``/boolean-condition/``)
|
|
// Or, if condition has commas `,` not already within parenthesis `(...)`.
|
|
BOOST_CONTRACT_ASSERT((``/boolean-condition/``))
|
|
|
|
This library will automatically call [funcref boost::contract::precondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if calling the functor specified via `.precondition(...)` throws an exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.).
|
|
|
|
[note
|
|
Contracts are most useful when their assertions only use public members that are accessible to the caller so the caller can properly check and use the contract.
|
|
In particular, preconditions of a public member function or constructor that use non-public members are essentially incorrect because they cannot be fully checked by the caller (in fact, Eiffel generates a compile-time error in this case).
|
|
|
|
This library leaves it up to the programmers to only use public members when programming contracts and especially when programming preconditions (see also __Specification_and_Implementation__).
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section Postconditions]
|
|
|
|
When postconditions are specified, they are programmed using a functor that can be called with no parameter [^['g]]`()` and it is passed to `.postcondition(`[^['g]]`)`.
|
|
Contracts that do not have postconditions simply do not call `.postcondition(...)`.
|
|
When both preconditions and postconditions are specified, postconditions must appear after preconditions (see __Preconditions__).
|
|
|
|
C++11 lambda functions are very convenient to program postconditions, but any other nullary functor can be used (see also __No_Lambda_Functions__).
|
|
For example, for [funcref boost::contract::function] (but same for all other contracts):
|
|
|
|
boost::contract::guard c = boost::contract::function() // Same for all other contracts.
|
|
...
|
|
.postcondition([&] { // Capture by reference...
|
|
BOOST_CONTRACT_ASSERT(...); // ...but should not modify captures.
|
|
...
|
|
})
|
|
;
|
|
|
|
The postcondition functor should capture all variables that it needs to assert the postconditions.
|
|
In general, these variables should be captured by reference and not by value (because postconditions need to access the value that these variables will have at function exit, and not the value these variables had when the postcondition functor was first constructed).
|
|
Postconditions can also capture return and old values (see __Return_Value__ and __Old_Values__).
|
|
In any case, postcondition assertions should not modify the value of the captured variables (see also __Constant_Correctness__).
|
|
|
|
Any code can be programmed for the postcondition functor, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex postconditions that might be buggy and slow to execute at run-time).
|
|
It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program postcondition assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, but see also __No_Macros__):
|
|
|
|
BOOST_CONTRACT_ASSERT(``/boolean-condition/``)
|
|
// Or, if condition has commas `,` not already within parenthesis `(...)`.
|
|
BOOST_CONTRACT_ASSERT((``/boolean-condition/``))
|
|
|
|
This library will automatically call [funcref boost::contract::postcondition_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if calling the functor specified via `.postcondition(...)` throws an exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.).
|
|
|
|
For non-void public functions, the functor passed to `.postcondition(...)` is not a nullary functor.
|
|
Instead, it is a unary functor taking a variable holding the return value as its one parameter (see also __Public_Functions__).
|
|
|
|
[endsect]
|
|
|
|
[section Return Value]
|
|
|
|
In non-void functions, postconditions can access the function return value to program assertions.
|
|
In this case, programmers are responsible to declare a local variable before the contract and to assign it to the return value at function exit (when the function does not throw an exception).
|
|
[footnote
|
|
The name of the local variable that holds the return value is arbitrary, but `result` is often used in this documentation.
|
|
]
|
|
For example, for [funcref boost::contract::function] (but same for all other contracts):
|
|
|
|
``/return-type/`` result; // Must be assigned to return value.
|
|
boost::contract::guard c = boost::contract::function() // Same for all other contracts.
|
|
...
|
|
.postcondition([&] { // Also capture `result` reference...
|
|
BOOST_CONTRACT_ASSERT(result ...); // ...but should not modify captures.
|
|
...
|
|
})
|
|
;
|
|
|
|
At any point where the enclosing function returns, programmers are responsible to assign the result variable to the expression being returned.
|
|
This can be easily done by making sure that /all/ `return` statements in the function are of the form:
|
|
|
|
return result = ``/expression/``; // Assign `result` at each return.
|
|
|
|
The functor used to program postconditions should capture the result variable by reference and not by value (because postconditions must access the value the result variable will have at function exit, and not the value the result variable had when the postcondition functor was first constructed).
|
|
The return value should never be used in preconditions (because the return value is not yet evaluated and set when preconditions are checked).
|
|
In any case, programmers should not modify the result variable in the contract assertions (see also __Constant_Correctness__).
|
|
|
|
It is also possible to declared the result variables using `boost::optional` when the function return type does not have a default constructor, or if the default constructor is too expensive or undesirable to execute (see __Optional_Return_Value__).
|
|
|
|
Non-void virtual and overriding public member functions must always declare and use a result variable even when postconditions do not directly use the function return value (so to properly support subcontracting, see __Virtual_Public_Functions__ and __Overriding_Public_Functions__).
|
|
|
|
[endsect]
|
|
|
|
[section Old Values]
|
|
|
|
When old values are used in postconditions, programmes are responsible to declare local variables before the contract and to assign them to related old value expressions using the [macroref BOOST_CONTRACT_OLDOF] macro.
|
|
[footnote
|
|
The name of the local variable that holds an old value is arbitrary, but [^old_['name]] is often used in this documentation.
|
|
]
|
|
For example, for [funcref boost::contract::function] (but same for all other contracts):
|
|
|
|
boost::contract::old_ptr<``/type/``> old_``/name/`` = BOOST_CONTRACT_OLDOF(``/expression/``);
|
|
boost::contract::guard c = boost::contract::function() // Same for all other contracts.
|
|
...
|
|
.postcondition([&] { // Capture by reference...
|
|
BOOST_CONTRACT_ASSERT(*old_``/name/`` ...); // ...but should not modify captures.
|
|
...
|
|
})
|
|
;
|
|
|
|
Old values are handled by this library using the smart pointer class template [classref boost::contract::old_ptr] (so programmers do not directly manage the allocation and deallocation of the pointed memory).
|
|
The pointed old value is automatically qualified as `const` (so old values cannot be mistakenly changed by the contract assertions, see also __Constant_Correctness__).
|
|
This library ensures that old value pointers are always not null by the time postconditions are checked (so programmers can safely dereference these pointers in postcondition assertions using `operator*` or `operator->` without having to check if old value pointers are not null first).
|
|
|
|
Old values should never be used in preconditions (because old values are the same as the original values when preconditions are checked).
|
|
This library does not even guarantee that old value pointers are not null when precondition functors are called (for example, when postcondition contract checking is disabled using [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], when checking an overridden virtual public function contract via subcontracting, etc.).
|
|
Finally, see __Old_Values_at_Body__ for delaying the assignment of old values until after preconditions (and possibly class invariants) are checked (this allows to program old value expressions under the simplifying assumption that precondition and class invariant assertions are satisfied already).
|
|
|
|
The [macroref BOOST_CONTRACT_OLDOF] macro is actually a variadic macro and it takes an extra parameter when used in virtual or overriding public functions (see __Virtual_Public_Functions__ and __Overriding_Public_Functions__).
|
|
C++11 auto declarations can be used with [macroref BOOST_CONTRACT_OLDOF] for brevity `auto `[^old_['name] = BOOST_CONTRACT_OLDOF(['expression])].
|
|
See __No_Macros__ to program old values without using [macroref BOOST_CONTRACT_OLDOF] (e.g., on compilers that do not support variadic macros).
|
|
|
|
This library ensures that old values are copied only once and that they are never copied when postcondition contract checking is disabled using [macroref BOOST_CONTRACT_NO_POSTCONDITIONS].
|
|
|
|
[endsect]
|
|
|
|
[section Class Invariants]
|
|
|
|
When class invariants are specified, they are programmed in a public `const` member function named `invariant` taking no argument and returning `void`.
|
|
Classes that do not have invariants, simply do not declare the `invariant` member function.
|
|
[footnote
|
|
This library uses template meta-programming (SFINAE-based introspection techniques) to check invariants only for classes that declare a member function named `invariant`.
|
|
]
|
|
For example:
|
|
|
|
class a {
|
|
public: // Must be public.
|
|
void invariant() const { // Must be const.
|
|
BOOST_CONTRACT_ASSERT(...);
|
|
...
|
|
}
|
|
|
|
...
|
|
};
|
|
|
|
This member function must be `const` because contracts should not modify the object state (see also __Constant_Correctness__).
|
|
This library will generate a compile-time error if the `const` qualifier is missing (unless the [macroref BOOST_CONTRACT_PERMISSIVE] macro is defined).
|
|
|
|
Any code can be programmed in the `invariant` function, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex invariants that might be buggy and slow to execute at run-time).
|
|
It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program class invariant assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, but see also __No_Macros__):
|
|
|
|
BOOST_CONTRACT_ASSERT(``/boolean-condition/``)
|
|
// Or, if condition has commas `,` not already within parenthesis `(...)`.
|
|
BOOST_CONTRACT_ASSERT((``/boolean-condition/``))
|
|
|
|
This library will automatically call [funcref boost::contract::entry_invariant_failure] or [funcref boost::contract::exit_invariant_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if the `invariant` function throws an exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.).
|
|
|
|
See __Access__ to avoid making the `invariant` member function `public`.
|
|
[footnote
|
|
In this documentation the `invariant` member function is often declared `public` for simplicity.
|
|
However, in most production code it might not be acceptable to augment the public members of a class adding `invariant` and [classref boost::contract::access] can be used to avoid that as explained in __Access__.
|
|
]
|
|
See the [macroref BOOST_CONTRACT_INVARIANT] macro to use a name different from `invariant` (e.g., because `invariant` clashes with other names in user-defined classes).
|
|
|
|
[note
|
|
No contracts are checked (not event class invariants) when a data member is accessed directly (this is different from Eiffel where even accessing public data members checks class invariants).
|
|
Therefore, it might be best for both `class`es and `struct`s that have invariants to have no mutable public data members and to access data members publicly only via appropriate public member functions that can check the class invariants.
|
|
]
|
|
|
|
[heading Static Class Invariants]
|
|
|
|
When static class invariants are specified, they are programmed in a public `static` member functions named `static_invariant` taking no argument and returning `void`.
|
|
Classes that do not have static class invariants, simply do not declare a `static_invariant` member function.
|
|
[footnote
|
|
This library uses template meta-programming (SFINAE-based introspection techniques) to check static invariants only for classes that declare a member function named `static_invariant`.
|
|
]
|
|
For example:
|
|
|
|
class a {
|
|
public: // Must be public.
|
|
static void static_invariant() { // Must be static.
|
|
BOOST_CONTRACT_ASSERT(...);
|
|
...
|
|
}
|
|
|
|
...
|
|
};
|
|
|
|
This member function must be `static` so it correctly cannot access the object `this`.
|
|
This library will generate a compile-time error if the `static` classifier is missing (unless the [macroref BOOST_CONTRACT_PERMISSIVE] macro is defined).
|
|
|
|
Any code can be programmed in the `static_invariant` function, but it is recommended to keep this code simple using mainly assertions and if-statements (to avoid programming complex static invariants that might be buggy and slow to execute at run-time).
|
|
It is also recommended to use the [macroref BOOST_CONTRACT_ASSERT] macro to program the assertions because it enables this library to print very informative error messages when the asserted conditions are evaluated to be false at run-time (this is not a variadic macro, but see also __No_Macros__):
|
|
|
|
BOOST_CONTRACT_ASSERT(``/boolean-condition/``)
|
|
// Or, if condition has commas `,` not already within parenthesis `(...)`.
|
|
BOOST_CONTRACT_ASSERT((``/boolean-condition/``))
|
|
|
|
This library will automatically call [funcref boost::contract::entry_invariant_failure] or [funcref boost::contract::exit_invariant_failure] if any of the [macroref BOOST_CONTRACT_ASSERT] macro conditions are `false` and also if the `static_invariant` function throws an exception (by default, this terminates the program calling `std::terminate`, but see __Throw_on_Failure__ to throw exceptions, exit the program with an error code, etc.).
|
|
|
|
See __Access__ to avoid making `static_invariant` member function `public`.
|
|
[footnote
|
|
In this documentation the `static_invariant` member function is often declared `public` for simplicity.
|
|
However, in most production code it might not be acceptable to augment the public members of a class adding `static_invariant` and [classref boost::contract::access] can be used to avoid that as explained in __Access__.
|
|
]
|
|
Set the [macroref BOOST_CONTRACT_STATIC_INVARIANT] macro to use a name different from `static_invariant` (e.g., because `static_invariant` clashes with other names in the user-defined class).
|
|
[footnote
|
|
*Rationale:*
|
|
In C++, it is not possible to overload a member function based on the `static` classifier.
|
|
Therefore, different function names have to be used for member functions checking static and non-static class invariants, namely `invariant` and `static_invariant`.
|
|
]
|
|
|
|
See __Volatile_Public_Functions__ for programming volatile class invariants.
|
|
|
|
[endsect]
|
|
|
|
[section Constructors]
|
|
|
|
Contracts for constructors are programmed using the [funcref boost::contract::constructor] function and the [classref boost::contract::constructor_precondition] base class.
|
|
For example (see also [@../../example/features/public.cpp =public.cpp=]):
|
|
|
|
[import ../example/features/public.cpp]
|
|
[public_constructor]
|
|
|
|
It is not possible to specify preconditions using `.precondition(...)` for constructors (the library will generate a compile-time error if `.precondition(...)` is used on the object returned by [funcref boost::contract::constructor]).
|
|
Constructor preconditions are specified using the [classref boost::contract:constructor_precondition] base class instead (see also __Preconditions__).
|
|
Programmes should not access the object `this` from constructor preconditions (because the object does not exists yet before the constructor body is executed, see also __No_Lambda_Functions__).
|
|
Constructors without preconditions simply do not explicitly initialize the [classref boost::contract::constructor_precondition] base (because [classref boost::contract::constructor_precondition] default constructor checks no contract).
|
|
When [classref boost::contract::constructor_precondition] is used:
|
|
[footnote
|
|
There is a MSVC bug that was fixed in MSVC 2013 for which lambdas cannot be used in constructor member initialization lists for templates.
|
|
On MSVC compilers with that bug, an external (static member) function can be used (together with `bind` and `cref` as needed) to program constructor preconditions instead of using lambdas.
|
|
]
|
|
|
|
* It should be specified as the /first/ class in the inheritance list (so constructor preconditions are checked before initializing any other base or member).
|
|
* Its inheritance level should always be `private` (so this extra base class does not alter the public inheritance tree of the derived class).
|
|
* It takes the derived class as template parameter (the Curiously Recursive Template Pattern (CRTP) is used here to avoid ambiguity errors with multiple inheritance).
|
|
[footnote
|
|
*Rationale:*
|
|
The [classref boost::contract::constructor_precondition] takes the derived class as its template parameter so the instantiated template type is unique for each derived class always avoiding base class ambiguities even in case of multiple inheritance.
|
|
Virtual inheritance cannot be used resolve such ambiguities because virtual bases are initialized only once by the out-most derived class, and that would not allow to properly check preconditions of all base classes.
|
|
]
|
|
|
|
It is possible to specify postconditions for constructors (see also __Postconditions__).
|
|
Programmers should not access the old value of the object `this` in constructor postconditions (because the object did not exist yet before the constructor body was executed, see also __No_Lambda_Functions__).
|
|
The [funcref boost::contract::constructor] function takes `this` as a parameter because constructors check class invariants (see also __Class_Invariants__).
|
|
|
|
The [funcref boost::contract::constructor] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::guard] otherwise this library will generate a run-time error (note that C++11 `auto` declarations cannot be used here and the [classref boost::contract::guard] type must be explicitly specified).
|
|
The constructor body is programmed right after the declaration of this RAII object.
|
|
At construction, this RAII object does the following:
|
|
|
|
# Check static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` (but not non-static class invariants because the object does not exists yet).
|
|
|
|
At destruction instead:
|
|
|
|
# Check static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()`.
|
|
# If the constructor body did not throw an exception:
|
|
# Check non-static class invariants, by calling `this->invariant()`.
|
|
# Check postconditions, by calling the nullary functor ['[^g]]`()` passed to `.postcondition(`['[^g]]`)`.
|
|
|
|
This together with C++ object construction mechanism of base classes and the use of [classref boost::contract::constructor_precondition] ensures that the constructor contracts are correctly checked at run-time (see also __Constructor_Calls__).
|
|
|
|
[note
|
|
A constructor can avoid calling [funcref boost::contract::constructor] for efficiency but only when it has no postconditions and its class has no invariants.
|
|
(Even if [funcref boost::contract::constuctor] is not used by a derived class, contracts of base classes will still be correctly checked by C++ object construction mechanism.)
|
|
|
|
The default constructor and copy constructor automatically generated by C++ will not check contracts.
|
|
Therefore, unless these constructors are not public or they have no preconditions, no postconditions, and the class has no invariants, programmers should manually define them using [funcref boost::contract::constructor] and [classref boost::contract::constructor_precondition].
|
|
(Same for all other automatically generated operations.)
|
|
]
|
|
|
|
Private and protected constructors can omit [funcref boost::contract::constructor] because they are not part of the public interface of the class so they are not required to check class invariants (see also __Constructor_Calls__).
|
|
They could still use [classref boost::contract::constructor_precondition] to check preconditions before member initializations, and use [funcref boost::contract::function] (but not [funcref boost::contract::constructor]) to only check postconditions without checking class invariants (see also __Private_and_Protected_Functions__).
|
|
|
|
[endsect]
|
|
|
|
[section Destructors]
|
|
|
|
Contracts for destructors are programmed using the [funcref boost::contract::destructor] function.
|
|
For example (see also [@../../example/features/public.cpp =public.cpp=]):
|
|
|
|
[public_destructor]
|
|
|
|
It is not possible to specify preconditions for destructors (the library will generate a compile-time error if `.precondition(...)` is used here because destructors can be called at any time after construction so they have no precondition).
|
|
It is possible to specify postconditions for destructors (see also __Postconditions__ for more information and see __Static_Public_Functions__ for an example).
|
|
Programmers should not access the object `this` in destructor postconditions (because the object no longer exists after the destructor body has been executed, see also __No_Lambda_Functions__).
|
|
The [funcref boost::contract::destructor] function takes `this` as a parameter because destructors check class invariants (see also __Class_Invariants__).
|
|
|
|
The [funcref boost::contract::destructor] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::guard] otherwise this library will generate a run-time error (note that C++11 `auto` declarations cannot be used here and the [classref boost::contract::guard] type must be explicitly specified).
|
|
The destructor body is programmed right after the declaration of this RAII object.
|
|
At construction, this RAII object does the following:
|
|
|
|
# Check static and non-static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()`.
|
|
|
|
At destruction instead:
|
|
|
|
# Check static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()`.
|
|
# If the destructor body threw an exception:
|
|
# Check non-static class invariants, by calling `this->invariant()` (because the object was not successfully destructed).
|
|
# Else:
|
|
# Check postconditions, by calling the nullay functor ['[^g]]`()` passed to `.postcondition(`['[^g]]`)`.
|
|
|
|
This together with C++ object destruction mechanism of base classes ensures that destructor contracts are correctly checked at run-time (see also __Destructor_Calls__).
|
|
|
|
[note
|
|
A destructor can avoid calling [funcref boost::contract::destructor] for efficiency but only when it has no postconditions and its class has no invariants.
|
|
(Even if [funcref boost::contract::destructor] is not used by a derived class, contracts of base classes will still be correctly checked by C++ object destruction mechanism.)
|
|
|
|
The default destructor automatically generated by C++ will not check contracts.
|
|
Therefore, unless the destructor is not public or it has no postconditions and the class has no invariants, programmers should manually define it using [funcref boost::contract::destructor].
|
|
(Same for all other automatically generated operations.)
|
|
]
|
|
|
|
Private and protected destructors can omit [funcref boost::contract::destructor] because they are not part of the public interface of the class so they are not required to check class invariants (see also __Destructor_Calls__).
|
|
They could use [funcref boost::contract::function] (but not [funcref boost::contract::destructor]) to only check postconditions without checking class invariants (see also __Private_and_Protected_Functions__).
|
|
|
|
[endsect]
|
|
|
|
[section Public Functions]
|
|
|
|
Contracts for public member functions are programmed using the [funcref boost::contract::public_function] function.
|
|
|
|
Let's consider public member functions that are not static, not virtual, and do not override any function from base classes.
|
|
For example, the following such a function `find` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/public.cpp =public.cpp=]):
|
|
|
|
[public_function]
|
|
|
|
It is possible to specify both preconditions and postconditions for public member functions (see also __Preconditions__ and __Postconditions__).
|
|
The [funcref boost::contract::public_function] function takes `this` as a parameter because public member functions check class invariants (see also __Class_Invariants__).
|
|
|
|
The [funcref boost::contract::public_function] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::guard] otherwise this library will generate a run-time error (note that C++11 `auto` declarations cannot be used here and the [classref boost::contract::guard] type must be explicitly specified).
|
|
The public member function body is programmed right after the declaration of this RAII object.
|
|
At construction, this RAII object does the following:
|
|
|
|
# Check static and non-static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()`.
|
|
# Check preconditions, by calling the nullary functor ['[^f]]`()` passed to `.precondition(`['[^f]]`)`.
|
|
|
|
At destruction instead:
|
|
|
|
# Check static and non-static class invariants, by calling ['[^typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()` (even if the function body threw an exception).
|
|
# If the function body did not throw an exception:
|
|
# Check postconditions, by calling the functor [^['g]]`()` passed to `.postcondition(`['[^g]]`)` (or [^['g]]`(`['result]`)` for non-void public functions).
|
|
|
|
This ensures that public member function contracts are correctly checked at run-time (see also __Public_Function_Calls__).
|
|
|
|
[note
|
|
A public member function can avoid calling [funcref boost::contract::public_function] for efficiency but only when it has no preconditions and no postconditions, it is not virtual, it does not override any virtual function, and its class has no invariant.
|
|
|
|
The default copy assignment operator automatically generated by C++ will not check contracts.
|
|
Therefore, unless this operator is not public or it has no preconditions, no postconditions, and the class has no invariants, programmers should manually define it using [funcref boost::contract::public_function].
|
|
(Same for all other automatically generated operations.)
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section Virtual Public Functions]
|
|
|
|
Let's consider public member functions that are virtual but that still do not override any function from base classes.
|
|
For example, the following such a function `push_back` is declared as a member of the `unique_identifiers` class (see also [@../../example/features/public.cpp =public.cpp=]):
|
|
|
|
[public_virtual_function]
|
|
|
|
Public virtual functions must declare an extra trailing parameter of type [classref boost::contract::virtual_]`*` with `0` default value (i.e., `nullptr`).
|
|
[footnote
|
|
The name of this extra parameter is arbitrary, but `v` is often used in this documentation.
|
|
]
|
|
This extra parameter is the last parameter and it has a default argument so it does not really alter the calling interface of the virtual function.
|
|
Callers will rarely have to explicitly deal with this extra parameter (a part from when manipulating the virtual function type directly as a function pointer, for function pointer type-casts, etc.).
|
|
Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls in the virtual function.
|
|
[footnote
|
|
*Rationale:*
|
|
The [classref boost::contract::virtual_]`*` optional parameter is used by this library to determine that a function is virtual (in C++ it is not possible to introspect if a function has been declared `virtual`).
|
|
Furthermore, this parameter is internally used by this library to pass result and old values that are evaluated by the overriding function to overridden virtual functions, and also to check preconditions and postconditions of overridden virtual functions when subcontracting (but without executing overridden function bodies).
|
|
]
|
|
|
|
The [funcref boost::contract::public_function] function takes `this` as a parameter because public virtual functions check class invariants (see also __Class_Invariants__).
|
|
As shown in the example above, when the public virtual function has a non-void return type programmers must pass a reference to the function return value as the second argument to [funcref boost::contract::public_function].
|
|
In this case the functor specified to `.postcondition(...)` takes a single parameter for the return value (possibly as a constant reference `const&` to avoid extra copies of the return value).
|
|
[footnote
|
|
*Rationale:*
|
|
The functor passed to `.postcondition(...)` takes the extra return value parameter because that is used by this library to pass the return value evaluated by the overriding function to all its overridden virtual functions when subcontracting.
|
|
]
|
|
|
|
[important
|
|
It is the responsibility of the programmers to pass the extra parameter `v` to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls within public virtual functions, and also to pass the return value reference after `v` to [funcref boost::contract::public_function] for non-void public virtual functions.
|
|
This library cannot automatically generate compile-time errors if programmers fail to do so (but in general contract checking will not correctly work at run-time).
|
|
[footnote
|
|
*Rationale:*
|
|
This library does not require the function type when using [funcref boost::contract::public_function] for non-overriding virtual functions.
|
|
Therefore, this library does not know if the enclosing function has a non-void return type so it cannot check if the return value reference is passed as required for non-overriding virtual functions.
|
|
Instead this library requires the function type for overriding virtual functions thus it gives a compile-time error if the return value reference is missing in those cases.
|
|
]
|
|
|
|
['Remember: always pass "v" as the first argument to old-of macros, the contract, etc. for public virtual functions; always pass the result variable after "`v`" to the contract for non-void virtual functions.]
|
|
]
|
|
|
|
For the rest, the same considerations made in __Public_Functions__ apply.
|
|
|
|
[endsect]
|
|
|
|
[section Public Function Overrides (Subcontracting)]
|
|
|
|
Let's consider public member functions (virtual or not) that override public virtual functions from one or more public base classes.
|
|
For example, the following such a function `push_back` is declared as a member of the `identifiers` derived class and it overrides `push_back` from the `unique_identifiers` base class (see also [@../../example/features/public.cpp =public.cpp=]):
|
|
[footnote
|
|
In this document, overriding functions are often marked with the comment `/* override */`.
|
|
On compilers that support C++11 virtual specifiers, the `override` identifier can be used instead (`override` is not used in the documentation only because virtual specifiers are not widely supported yet, even by compilers that support C++11 lambda functions, etc.).
|
|
]
|
|
|
|
[public_function_override]
|
|
|
|
The extra `typedef` that uses the [macroref BOOST_CONTRACT_BASE_TYPES] macro is required by this library for derived classes and it is internally used detect base classes for subcontracting (see __Base_Classes__).
|
|
|
|
When called from overriding public functions, [funcref boost::contract::public_function] takes an explicit template argument `override_`[^['function-name]] that must be defined by:
|
|
|
|
BOOST_CONTRACT_OVERRIDE(``['function-name]``)
|
|
|
|
This can be used at any point in the public section of the enclosing class (see __Access__ to use [macroref BOOST_CONTRACT_OVERRIDE] in a non-public section of the class instead).
|
|
The [macroref BOOST_CONTRACT_OVERRIDE] macro must be used only once in a class for a given function name and overloaded functions can reuse the same [^override_['function-name]] definition (plus [macroref BOOST_CONTRACT_NAMED_OVERRIDE] can be used to generate a name different than [^override_['function-name]], see also __Overloads_and_Named_Overrides__).
|
|
This library will generate a compile-time error if there is no suitable virtual function to override in any of the public base classes.
|
|
[footnote
|
|
This error is similar in principle to the error generated by C++11 `override` specifier, but it is limited to functions with the extra [classref boost::contract::virtual_]`*` parameter and searched recursively only in `public` base classes passed to [macroref BOOST_CONTRACT_BASE_TYPES] because only those are valid functions to override for subcontracting.
|
|
]
|
|
|
|
For convenience [macroref BOOST_CONTRACT_OVERRIDES] can be used with multiple functions names instead of repeating [macroref BOOST_CONTRACT_OVERRIDE] for each function name (on compilers that support variadic macros):
|
|
|
|
BOOST_CONTRACT_OVERRIDES(``[^['function-name1]]``, ``[^['function-name2]]``, ...)
|
|
|
|
Which is equivalent to:
|
|
|
|
BOOST_CONTRACT_OVERRIDE(``[^['function-name1]]``)
|
|
BOOST_CONTRACT_OVERRIDE(``[^['function-name2]]``)
|
|
...
|
|
|
|
Overriding public functions must always list the extra trailing parameter of type [classref boost::contract::virtual_]`*` with `0` default value (i.e., `nullptr`), even when they are not declared `virtual` (because this parameter is present in the signature of the virtual function being overridden from base classes).
|
|
Programmers must pass the extra virtual parameter as the very first argument to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls in the overriding function.
|
|
|
|
When called from overriding public functions, [funcref boost::contract::public_function] also takes a pointer to the enclosing function, the object `this` (because overriding public functions check class invariants), and references to each function argument in the order they appear in the function declaration.
|
|
[footnote
|
|
*Rationale:*
|
|
The object `this` is passed after the function pointer to follow `bind`'s syntax.
|
|
The function pointer and references to all function arguments are needed for overriding virtual public functions because this library has to call overridden virtual public functions to check their contracts for subcontracting (even if this library will not actually execute the bodies of the overridden functions).
|
|
]
|
|
As shown in the example above, when the overriding public function has a non-void return type, programmers must pass a reference to the function return value as the second argument to [funcref boost::contract::public_function] (this library will generate a compile-time error otherwise).
|
|
[footnote
|
|
*Rationale:*
|
|
As for non-overriding public virtual functions, also overriding functions use the extra return value parameter to pass it to the overridden functions when subcontracting.
|
|
In the case of overriding functions this library also has the function pointer so it will generate a compile-time error if the function is non-void and programmers forget to specify the extra return value parameter (this extra error checking is not possible instead for non-overriding public virtual functions because their contracts do not have to specify the function pointer, see also __Virtual_Public_Functions__).
|
|
]
|
|
In this case the functor specified to `.postcondition(...)` takes a single parameter for the return value (possibly as a constant reference `const&` to avoid extra copies of the return value).
|
|
|
|
[important
|
|
It is the responsibility of the programmers to pass the extra parameter `v` to all [macroref BOOST_CONTRACT_OLDOF] and [funcref boost::contract::public_function] calls within overriding public functions, and also to pass the return value reference after `v` to [funcref boost::contract::public_function] for non-void overriding public functions.
|
|
This library cannot always generate compile-time errors if programmers fail to do so (but in general contract checking will not correctly work at run-time).
|
|
|
|
['Remember: always pass "v" as the first argument to old-of macros, the contract, etc. for overriding public functions; always pass the result variable after "`v`" to the contract for non-void overriding public functions.]
|
|
]
|
|
|
|
The [funcref boost::contract::public_function] function returns an RAII object that must always be assigned to a local variable of type [classref boost::contract::guard] otherwise this library will generate a run-time error (note that C++11 `auto` declarations cannot be used here and the [classref boost::const::guard] type must be explicitly specified).
|
|
The public member function body is programmed right after the declaration of this RAII object.
|
|
At construction, this RAII object doe the following:
|
|
|
|
# Check static and non-static class invariants for all overridden bases and for the derived class, by calling [^['typeof](['overridden-base])]`::static_invariant()` __AND__ [^['overridden-base]]`.invariant()` __AND__... [^['typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()`.
|
|
# Check preconditions for all overridden base functions and for the overriding derived function in __OR__ with each other, by calling the nullary functors [^['f1]]`()` __OR__... [^['fn]]`()` passed to `.precondition(`[^['f1]]`)`, ..., `.precondition(`[^['fn]]`)` for all of the overridden and overriding functions respectively.
|
|
|
|
At destruction instead:
|
|
|
|
# Check static and non-static class invariants for all overridden bases and for the derived class, by calling [^['typeof](['overridden-base])]`::static_invariant()` __AND__ [^['overridden-base]]`.invariant()` __AND__... [^['typeof]]`(*this)::static_invariant()` __AND__ `this->invariant()` (even if the function body threw an exception).
|
|
# If the function body did not throw an exception:
|
|
# Check postconditions for all overridden base functions and for the overriding derived function in __AND__ with each other, by calling the functors [^['g1]]`()` __AND__... [^['gn]]`()` passed to `.postcondition(`[^['g1]]`)`, ..., `.postcondition(`[^['gn]]`)` for all of the overridden and overriding functions respectively (or [^['g1]]`(`[^['result]]`)` __AND__... [^['gn]]`(`[^['result]]`)` for non-void public function overrides).
|
|
|
|
This ensures that overriding public function subcontracts are checked correctly at run-time (see also __Public_Function_Calls__).
|
|
|
|
For the rest, the same considerations made in __Public_Virtual_Functions__ apply.
|
|
|
|
[endsect]
|
|
|
|
[section Base Classes (Subcontracting)]
|
|
|
|
In order for this library to support subcontracting, programmers must specify the bases of a class declaring a public member type named `base_types` via a `typedef` using [macroref BOOST_CONTRACT_BASE_TYPES].
|
|
For example (see also [@../../example/features/base_types.cpp =base_types.cpp=]):
|
|
|
|
[import ../example/features/base_types.cpp]
|
|
[base_types]
|
|
|
|
For convenience, a /local macro/ named `BASES` can be used to avoid repeating the base list twice (first when inheriting [^: ['base-list]] and then when invoking [macroref BOOST_CONTRACT_BASE_TYPES][^(['base-list])]).
|
|
Being a local macro, `BASES` must be undefined using `#undef BASES` after it has been used to declare `base_types` (to avoid macro redefinition errors).
|
|
[footnote
|
|
In this documentation, the local macro to declare base classes is often named `BASES` but any other name can be used.
|
|
]
|
|
|
|
[macroref BOOST_CONTRACT_BASE_TYPES] is a variadic macro and accepts a list of bases separated by commas (see __No_Macros__ to program `base_types` without using macros).
|
|
When the extra base [classref boost::contract::constructor_precondition] is used to program constructor preconditions, it must always be private and appear as the very first base (see also __Constructors__).
|
|
|
|
[important
|
|
Each base passed to [macroref BOOST_CONTRACT_BASE_TYPES] must /explicitly/ specify its inheritance access level `public`, `protected`, or `private` (`virtual` is optional and can be specified either before or after the access level as usual in C++).
|
|
[footnote
|
|
*Rationale:*
|
|
This library explicitly requires the inheritance access level because derived classes must subcontract only from public bases, but not from protected or private bases (see __Public_Function_Calls__).
|
|
Therefore, [macroref BOOST_CONTRACT_BASE_TYPES] inspect each inheritance access level (using preprocessor meta-programming) and removes non-public bases from the list bases `base_types` to consider for subcontracting.
|
|
]
|
|
This library will generate a compiler-error if the first base is missing its inheritance access level, but this library will not be able to error if the access level is missing from bases after the first one.
|
|
|
|
It is the responsibility of the programmers to make sure that all bases passed to [macroref BOOST_CONTRACT_BASE_TYPES] explicitly specify their inheritance access level (inheritance access levels are instead optional in C++ because `private` is implicitly assumed for `class` types and `public` for `struct` types).
|
|
]
|
|
|
|
See __Access__ to avoid making `base_types` member type `public` (e.g., in cases when all public members of a class including `typedef`s must be controlled exactly).
|
|
Set the [macroref BOOST_CONTRACT_BASE_TYPEDEF] configuration macro to use a name different from `base_types` (e.g., because `base_types` clashes with other names in the user-defined class).
|
|
|
|
[endsect]
|
|
|
|
[section Static Public Functions]
|
|
|
|
Let's consider static public member functions.
|
|
For example, the following such a function `instances` is declared as a member of the `make` class template (see also [@../../example/features/static_public.cpp =static_public.cpp=]):
|
|
|
|
[import ../example/features/static_public.cpp]
|
|
[static_public]
|
|
|
|
When called from static public functions, [funcref boost::contract::public_function] cannot take the object `this` as a parameter (because there is no object `this` in static member functions) so the enclosing class type (necessary to check static class invariants, see also __Static_Class_Invariants__) is specified as an explicit template parameter.
|
|
Even if they are not present in the example above, it is possible to specify preconditions and postconditions for static public member functions using `.precondition(...)` and `.postcondition(...)` as usual (see also __Preconditions__ and __Postconditions__).
|
|
|
|
The [funcref boost::contract::public_function] function returns an RAII object that must be assigned to a local variable of type [classref boost::contract::guard] otherwise this library will generate a run-time error (note that C++11 `auto` declarations cannot be used here and the [classref boost::contract::guard] type must be explicitly specified).
|
|
The static public member functions body is programmed right after the declaration of this RAII object.
|
|
At construction, this RAII object does the following:
|
|
|
|
# Check static class invariants, by calling [^['class-type]]`::static_invariant()` (but never non-static class invariants).
|
|
# Check preconditions, by calling the nullary functor [^['f]]`()` passed to `.precondition(`[^['f]]`)`.
|
|
|
|
At destruction instead:
|
|
|
|
# Check static class invariants, by calling [^['class-type]]`::static_invariant()` (even if the function body threw and exception, but never non-static class invariants).
|
|
# If the function body did not throw an exception:
|
|
# Check postconditions, by calling the nullary functor [^['g]]`()` passed to `.postcondition(`[^['g]]`)`.
|
|
|
|
This ensures that static public member function contracts are correctly checked at run-time (note that static public member functions do not subcontract, see also __Public_Function_Calls__).
|
|
|
|
[note
|
|
A static public member function can avoid calling [funcref boost::contract::public_function] for efficiency but only when it has no preconditions, no postconditions, and its class has no static invariants (the class can still have non-static invariants or base classes instead).
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section Private and Protected Functions]
|
|
|
|
Private and protected member functions do not check class invariants (because they are not part of the public class interface) and they do not subcontract (because they are not accessible at the calling site where the __substitution_principle__ applies, see also __Function_Calls__).
|
|
However, programmers can still choose to specify preconditions and postconditions for private and protected member functions if they want to check correctness of implementations and usage of base member functions in derived classes.
|
|
Therefore, when programmers decide to specify contracts for private and protected member functions, they can use [funcref boost::contract::function] (like for non-member functions).
|
|
For example (see also [@../../example/features/private_protected.cpp =private_protected.cpp=]):
|
|
|
|
[import ../example/features/private_protected.cpp]
|
|
[private_protected]
|
|
|
|
The same considerations made in __Non_Member_Functions__ apply.
|
|
|
|
See __Constructors__ and __Destructors__ for notes on how to program contracts for private and protected constructors and destructors respectively.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|