From f3721a747d31a2277c8a48663213b72ecf77c005 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Wed, 21 Aug 2019 21:27:46 -0700 Subject: [PATCH] finished to review extra doc section --- doc/extras.qbk | 133 +++++++++++----------- example/features/move.cpp | 4 +- example/features/union.cpp | 8 +- include/boost/contract/core/config.hpp | 4 +- include/boost/contract/core/exception.hpp | 6 +- include/boost/contract/core/specify.hpp | 8 +- include/boost/contract_macro.hpp | 4 +- 7 files changed, 86 insertions(+), 81 deletions(-) diff --git a/doc/extras.qbk b/doc/extras.qbk index 28fb989c..ea0a599d 100644 --- a/doc/extras.qbk +++ b/doc/extras.qbk @@ -281,11 +281,11 @@ If programmers need non-volatile public functions to also check `const volatile` [section Move Operations] As with all public operations of a class, also public move operations should maintain class invariants (see __Stroustrup13__, p. 520). -Specifically, C++ requires the following: +Specifically, at a minimum C++ requires the following: * The moved-from object can be copy assigned. * The moved-from object can be move assigned. -* The moved-from object can be destroyed (if not for anything else, this requires that class invariants are maintained by move operations because the destructor of the moved-from object requires class invariants to be satisfied at its entry, as always with destructors see __Destructor_Calls__). +* The moved-from object can be destroyed (if not for any other reason, this requires that class invariants are maintained by move operations because the destructor of the moved-from object requires class invariants to be satisfied at its entry, as always with destructors see __Destructor_Calls__). Therefore, both the move constructor and the move assignment operator need to maintain the class invariants of the moved-from object so their contracts can be programmed using [funcref boost::contract::constructor] and [funcref boost::contract::public_function] as usual. For example (see [@../../example/features/move.cpp =move.cpp=]): @@ -295,8 +295,8 @@ For example (see [@../../example/features/move.cpp =move.cpp=]): This example assumes that it is possible to call the public function `moved()` on the moved-from object. [footnote -In this example, the `moved()` function is simple enough that programmers could decide to not even call [funcref boost::contract::public_function] from it. -However, calling [funcref boost::contract::public_function] from `moved()` has no negative impact a part from run-time overhead because this library already automatically disables contract checking while checking other contracts (so this call will not cause infinite recursion). +In this example, the `moved()` function is simple enough that programmers could decide to not even call [funcref boost::contract::public_function] from it for optimization reasons. +However, calling [funcref boost::contract::public_function] from `moved()` has no negative impact, a part from run-time overhead, because this library automatically disables contract checking while checking other contracts (so this call will not cause infinite recursion). ] [note @@ -306,14 +306,14 @@ Therefore, unless the move operations are not public or they have no preconditio ] As always, programmers can decide to not program contracts for a given type. -Specifically, they might decide to not program contracts for a class that needs to be moved in order to skip the run-time overhead of checking contract assertions to optimize performance (see __Benefits_and_Costs__). +Specifically, they might decide to not program contracts for a class that needs to be moved in order to avoid the run-time overhead of checking contract assertions and to maximize performance (see __Benefits_and_Costs__). [endsect] [section Unions] -In C++, a `union` cannot have virtual functions, bases classes, and cannot be used as a base class thus subcontracting ([classref boost::contract::virtual_], [macroref BOOST_CONTRACT_OVERRIDE], etc.) do not apply to unions. -Also a `union` cannot inherit from [classref boost::contract::constructor_precondition] (because it cannot have base classes) so such a class is used to declare a local object that checks constructor preconditions (at the very beginning of the constructor before old value copies and other contracts, see declaration of `pre` in the example below). +A C++ `union` cannot have virtual functions, base classes, and cannot be used as a base class thus subcontracting ([classref boost::contract::virtual_], [macroref BOOST_CONTRACT_OVERRIDE], etc.) do not apply to unions. +Also a `union` cannot inherit from [classref boost::contract::constructor_precondition] (because it cannot have base classes), instead [classref boost::contract::constructor_precondition] is used to declare a local object that checks constructor preconditions (at the very beginning of the constructor before old value copies and other contracts, see declaration of `pre` in the example below). A part from that, this library is used as usual to program contracts for unions. For example (see [@../../example/features/union.cpp =union.cpp=]): @@ -326,15 +326,15 @@ For example (see [@../../example/features/union.cpp =union.cpp=]): This library provides three predefined /assertion levels/ that can be used to selectively disable assertions depending on their computational complexity: [footnote -The assertion levels predefined by this library are similar to the default, audit, and axiom levels proposed in __P0380__. +The assertion levels predefined by this library are similar to the default, audit, and axiom levels from __P0380__. ] * [macroref BOOST_CONTRACT_ASSERT] is used to assert conditions that are not computationally expensive, at least compared to the cost of executing the function body. -These assertions are always checked at run-time, they are not disabled. +These assertions are the ones we have seen so far, they are always checked at run-time and they cannot be disabled. * [macroref BOOST_CONTRACT_ASSERT_AUDIT] is used to assert conditions that are computationally expensive compared to the cost of executing the function body. -These assertions are not checked at run-time unless programmers explicitly define [macroref BOOST_CONTRACT_AUDITS] (undefined by default), but the conditions are always compiled and validated syntactically (even when they are not actually evaluated and checked at run-time). +These assertions are not checked at run-time unless programmers explicitly define [macroref BOOST_CONTRACT_AUDITS] (undefined by default), but the asserted conditions are always compiled and therefore validated syntactically (even when they are not actually evaluated and checked at run-time). * [macroref BOOST_CONTRACT_ASSERT_AXIOM] is used to assert conditions that are computationally prohibitive, at least compared to the cost of executing the function body. -These assertions are never evaluated or checked at run-time, but the asserted conditions are always compiled and validated syntactically so these assertions can serve as formal comments in the code. +These assertions are never evaluated or checked at run-time, but the asserted conditions are always compiled and therefore validated syntactically (so these assertions can serve as formal comments to the code). In addition, [macroref BOOST_CONTRACT_CHECK_AUDIT] and [macroref BOOST_CONTRACT_CHECK_AXIOM] are similar to [macroref BOOST_CONTRACT_ASSERT_AUDIT] and [macroref BOOST_CONTRACT_ASSERT_AXIOM] but they are used to program audit and axiom levels for implementation checks instead of assertions (see __Implementation_Checks__). @@ -357,42 +357,42 @@ For example, (see [@../../example/features/assertion_level.cpp =assertion_level. [assertion_level_axiom] [assertion_level_class_end] -In addition to the assertion levels predefined by this library, programmers are free to define their own. +In addition to these assertion levels that are predefined by this library, programmers are free to define their own. For example, the following macro could be used to program and selectively disable assertions that have exponential computational complexity `O(e^n)`: - #ifdef NO_EXPONENTIALLY_COMPLEX_ASSERTIONS - // Following will compile but never actually evaluate `cond`. - #define EXP_ASSERTION(cond) BOOST_CONTRACT_ASSERT(true || (cond)) - #else + #ifdef EXPONENTIALLY_COMPLEX_ASSERTIONS // Following will compile and also evaluate `cond`. - #define EXP_ASSERTION(cond) BOOST_CONTRACT_ASSERT(cond) + #define ASSERT_EXP(cond) BOOST_CONTRACT_ASSERT(cond) + #else + // Following will compile but never actually evaluate `cond`. + #define ASSERT_EXP(cond) BOOST_CONTRACT_ASSERT(true || (cond)) #endif ... - EXP_ASSERTION(``[^['some-exponentially-complex-boolean-condition]]``); + ASSERT_EXP(``[^['some-exponentially-complex-boolean-condition]]``); [endsect] [section Disable Contract Checking] Checking contracts adds run-time overhead and can slow down program execution (see __Benefits_and_Costs__). -Therefore, programmers can define any combination of the following macros (`-D` option in Clang and GCC, `/D` option in MSVC, etc.) to instruct this library to not check specific kind of contract conditions at run-time: +Therefore, programmers can define any combination of the following macros (`-D` option in Clang and GCC, `/D` option in MSVC, etc.) to instruct this library to not check specific groups of contract conditions at run-time: * Define [macroref BOOST_CONTRACT_NO_PRECONDITIONS] to not check preconditions. * Define [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] to not check postconditions. * Define [macroref BOOST_CONTRACT_NO_EXCEPTS] to not check exception guarantees. * Define [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] to not check class invariants at call entry. * Define [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS] to not check class invariants at call exit. -* Or, define [macroref BOOST_CONTRACT_NO_INVARIANTS] to not check class invariants at both call entry and exit. (This is provided for convenience, it is equivalent to define both [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS].) -* Define [macroref BOOST_CONTRACT_NO_CHECKS] to not perform implementation checks. +* Or, define [macroref BOOST_CONTRACT_NO_INVARIANTS] to not check class invariants at both call entry and exit. (This is provided for convenience, it is equivalent to defining both [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS].) +* Define [macroref BOOST_CONTRACT_NO_CHECKS] to not evaluate implementation checks. [note Old values can be used by both postconditions and exception guarantees so it is necessary to define both [macroref BOOST_CONTRACT_NO_POSTCONDITIONS] and [macroref BOOST_CONTRACT_NO_EXCEPTS] to disable old value copies. ] By default, none of these macros are defined so this library checks all contracts. -When these macros are defined by the user, the implementation code of this library is internally optimized to minimize as much as possible any run-time and compile-time overhead associated with checking and compiling contracts (see __Disable_Contract_Compilation__ for techniques to completely remove any run-time and compile-time overhead associated with contract code). +When these macros are defined by the user, the implementation code of this library is internally optimized to minimize as much as possible any run-time and compile-time overhead associated with checking and compiling contracts (see __Disable_Contract_Compilation__ for techniques to completely remove any run-time and compile-time overheads associated with contract code). For example, programmers could decide to check all contracts during early development builds, but later check only preconditions and maybe entry invariants for release builds by defining [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], [macroref BOOST_CONTRACT_NO_EXCEPTS], [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS], and [macroref BOOST_CONTRACT_NO_CHECKS]. @@ -400,7 +400,7 @@ For example, programmers could decide to check all contracts during early develo [section Disable Contract Compilation (Macro Interface)] -This library provides macros that can be used to completely disable compile-time and run-time overhead introduced by contracts but at the cost of manually programming `#ifndef` statements around contract code: +This library provides macros that can be used to completely disable compile-time and run-time overhead introduced by contracts but at the cost of manually programming `#ifndef BOOST_CONTRACT_NO_...` statements around contract code: * This library defines [macroref BOOST_CONTRACT_NO_CONSTRUCTORS] when contract checking is disabled for constructors. * This library defines [macroref BOOST_CONTRACT_NO_DESTRUCTORS] when contract checking is disabled for destructors. @@ -409,11 +409,11 @@ This library provides macros that can be used to completely disable compile-time * This library defines [macroref BOOST_CONTRACT_NO_OLDS] when old value copies are disabled. * This library defines [macroref BOOST_CONTRACT_NO_ALL] when all contracts above and also implementation checks (see [macroref BOOST_CONTRACT_NO_CHECKS]) are disabled. -These macros are not configuration macros and they should not be defined directly by programmers (otherwise this library will generate a compile-time error). +These macros are not configuration macros and they should not be defined directly by programmers (otherwise this library will generate compile-time errors). Instead, these macros are automatically defined by this library when programmers define [macroref BOOST_CONTRACT_NO_PRECONDITIONS], [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], [macroref BOOST_CONTRACT_NO_EXCEPTS], [macroref BOOST_CONTRACT_NO_INVARIANTS] (or [macroref BOOST_CONTRACT_NO_ENTRY_INVARIANTS] and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS]), and [macroref BOOST_CONTRACT_NO_CHECKS] (see __Disable_Contract_Checking__). -Alternatively, this library provides a macro-based interface [headerref boost/contract_macro.hpp] that can also be used to completely disable compile-time and run-time overhead introduced by contracts. -For example, the following code shows how to use both the macro interface and the `#ifndef BOOST_CONTRACT_NO_...` statements to completely disable compile-time and run-time overhead for non-member function contracts (see [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.cpp =ifdef.cpp=]): +Alternatively, this library provides a macro-based interface defined in [headerref boost/contract_macro.hpp] that can also be used to completely disable compile-time and run-time overheads introduced by contracts but without the burden of manually writing the `#ifndef BOOST_CONTRACT_NO_...` statements. +For example, the following code shows how to use both the [headerref boost/contract_macro.hpp] macro interface and the `#ifndef BOOST_CONTRACT_NO_...` statements to completely disable compile-time and run-time overheads for non-member function contracts (see [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.cpp =ifdef.cpp=]): [import ../example/features/ifdef_macro.cpp] [import ../example/features/ifdef.cpp] @@ -424,7 +424,8 @@ For example, the following code shows how to use both the macro interface and th The same can be done to disable contract code complication for private and protected functions. The [macroref BOOST_CONTRACT_OLD_PTR_IF_COPYABLE] macro is provided to handle non-copyable old value types (similar to [classref boost::contract::old_ptr_if_copyable]). -For constructors, destructors, and public functions instead (see [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.cpp =ifdef.cpp=]): + +For constructors, destructors, and public functions the [headerref boost/contract_macro.hpp] macro interface and the `#ifndef BOOST_CONTRACT_NO_...` statements can be used as follow (see [@../../example/features/ifdef_macro.cpp =ifdef_macro.cpp=] and [@../../example/features/ifdef.cpp =ifdef.cpp=]): [table [ [Macro Interface] [`#ifndef BOOST_CONTRACT_NO_...` Statements] ] @@ -433,15 +434,15 @@ For constructors, destructors, and public functions instead (see [@../../example Static and volatile class invariants can be programmed using [macroref BOOST_CONTRACT_STATIC_INVARIANT] and [macroref BOOST_CONTRACT_INVARIANT_VOLATILE] respectively (these macros expand code equivalent to the `static void BOOST_CONTRACT_STATIC_INVARIANT_FUNC()` and `void BOOST_CONTRACT_INVARIANT_FUNC() const volatile` functions). -The macro interface is usually preferred because more concise and easier to use than programming `#ifndef BOOST_CONTRACT_NO_...` statements by hand. -However, C++ macros expand on a single line of code and that can make compiler errors less useful when using the macro interface plus all contract assertions within a given set of preconditions, postconditions, exception guarantees, and class invariants will list the same line number in error messages when assertions fail at run-time (but error messages still list the assertion code and that should allow programmers to identify the specific assertion that failed). -Finally, the macro interface leaves a bit of contract decorations in the code but that should add no measurable compile-time and run-time overhead (specifically, extra [classref boost::contract::virtual_]`*` parameters, calls to [classref boost::contract::constructor_precondition] default constructor which does nothing, [macroref BOOST_CONTRACT_BASE_TYPES] `typedef`s, and [classref boost::contract::access] friendships are left in user code even when contracts are disabled). +The [headerref boost/contract_macro.hpp] macro interface is usually preferred because more concise and easier to use than programming `#ifndef BOOST_CONTRACT_NO_...` statements by hand. +However, C++ macros expand on a single line of code and that can make compiler errors less useful when using this macro interface plus all contract assertions within a given set of preconditions, postconditions, exception guarantees, and class invariants will list the same line number in error messages when assertions fail at run-time (but error messages still list the assertion code and that should still allow programmers to identify the specific assertion that failed). +Finally, the macro interface leaves a bit of contract decorations in the code but that should add no measurable compile-time or run-time overhead (specifically, extra [classref boost::contract::virtual_]`*` parameters, calls to [classref boost::contract::constructor_precondition] default constructor which does nothing, [macroref BOOST_CONTRACT_BASE_TYPES] `typedef`s, and [classref boost::contract::access] friendships are left in user code even when contracts are disabled unless `#ifndef BOOST_CONTRACT_NO_...` statements are used). Disabling contract as shown in __Disable_Contract_Checking__ leaves the overhead of compiling contract code plus some small run-time overhead due to the initialization of old value pointers (even if those will be all null and no old value will be actually copied), the calls to the contract functions used to initialize [classref boost::contract::check] and [classref boost::contract::constructor_precondition] (even if those calls will be internally optimized by this library to essentially do nothing), etc. For truly performance critical code for which even such small run-time overhead might not be acceptable, the macro interface (or the `#ifndef BOOST_CONTRACT_NO_...` statements) can be used to completely disable compile-time and run-time overheads of contracts. However, for such performance critical code even the overhead of checking simple preconditions might be too much so it might be best to not program contracts at all. -Usually, if the overhead of checking preconditions and other assertions is already considered acceptable for an application then the compile-time overhead of contracts should not represent an issue and it should be sufficient to be able to disable contract checking at run-time as indicated in __Disable_Contract_Checking__ (without a real need to use the macro interface or the `#ifndef BOOST_CONTRACT_NO_...` statements in most cases). +Usually, if the overhead of checking preconditions and other assertions is already considered acceptable for an application then the compile-time overhead of contracts should not represent an issue and it should be sufficient to disable contract checking at run-time as indicated in __Disable_Contract_Checking__ (without a real need to use the [headerref boost/contract_macro.hpp] macro interface or the `#ifndef BOOST_CONTRACT_NO_...` statements in most cases). [endsect] @@ -453,16 +454,17 @@ This is not ideal (even if contracts programmed using this library will always a In some cases, it might be desirable to completely separate the contract code from the function implementation code. For example, this could be necessary for software that ships only header files and compiled object files to its users. -If contracts are programmed in function definitions that are compiled in the object files, users will not be able to see the contract code to understand semantics and usage of the functions (again, this might not be a real problem in practice for example if contracts are already somehow extracted from the source code by some toll and presented as part of the documentation of the shipped software). +If contracts are programmed in function definitions that are compiled in the object files, users will not be able to see the contract code to understand semantics and usage of the functions (again, this might not be a real problem in practice for example if contracts are already somehow extracted from the source code by some tool and presented as part of the documentation of the shipped software). -In any case, when it is truly important to separate contracts from function implementation code, function implementations can be programmed in extra /body functions/ (e.g., named `..._body`) that are compiled in object files. -Function definitions that remain in header files instead will contain just contract code followed by calls the extra body functions. -This technique allows to keep the contract code in header files while separating the implementation code to object files. -However, it adds the overhead of manually programming an extra function declaration for the body function (plus the limitation that constructor member initialization lists must be programmed in header files because that is where constructors need to be defined to list constructor contract code). +In any case, when it is truly important to separate contracts from function implementation code, function implementations can be programmed in extra /body functions/ (here named `..._body`, but any other naming scheme could be used) that are compiled in object files. +Function definitions that remain in header files instead will contain just contract code followed by calls to the extra body functions. +This technique allows to keep the contract code in header files while separating the implementation code to source and object files. +However, this adds the overhead of manually programming an extra function declaration for each body function (plus the limitation that constructor member initialization lists must be programmed in header files because that is where constructors need to be defined to list constructor contract code). [footnote When used as default parameter values, lambda functions allow to program code statements within function declarations. -However, these lambadas cannot be effectively used to program contracts because the C++11 standard does not allow them to capture any variable (it would be not at all obvious how to correctly define the semantics of such captures). -For example, the following code does not compile: +However, these lambadas cannot be effectively used to program contracts in function declarations instead of definitions. +That is because the C++11 standard does not allow lambdas in function declarations to capture any variable (for the good reason that it is not at all obvious how to correctly define the semantics of such captures). +For example, the following code is not valid C++ and it does not compile: `` // Specifications (in declaration). int inc(int& x, @@ -506,7 +508,7 @@ Instead, the function bodies are implemented in a separate source file (see [@.. [import ../example/features/separate_body.cpp] [separate_body_cpp] -The same technique can be used for non-member, private, protectee functions, etc. +The same technique can be used for non-member, private, and protected functions, etc. [note When contracts are programmed only in =.cpp= files and also all this library headers are `#include`d only from =.cpp= files, then these =.cpp= files can be compiled disabling specific contract checking (for example, [macroref BOOST_CONTRACT_NO_POSTCONDITIONS], [macroref BOOST_CONTRACT_NO_EXCEPTS], and [macroref BOOST_CONTRACT_NO_EXIT_INVARIANTS], see __Disable_Contract_Checking__). @@ -525,24 +527,26 @@ This section shows how to use this library without C++11 lambda functions. This has some advantages: * It allows to use this library on compilers that do not support C++11 lambda functions (essentially most C++03 compilers with adequate support for SFINAE can be used in that case, see __No_Macros__ to also avoid using variadic macros). -* Contract functions (i.e., the `..._precondition`, `..._old`, and `..._postcondition` functions in the example below) can be programmed to fully enforce constant-correctness and other contract requirements at compile-time (see __Constant_Correctness__). -[footnote -If C++ allowed lambda functions to capture variables by constant reference (for example using the syntax `[const&] { ... }` and `[const& `[^['variable-name]]`] { ... }`, see [@https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/0UKQw9eo3N0]) also lambdas could be used to program contract functors that fully enforce __Constant_Correctness__ at compile-time. -Note that C++11 lambdas allow to capture variables by value (using `[=] { ... }` and `[`[^['variable-name]]`] { ... }`), these value captures are `const` (unless the lambda is explicitly declared `mutable`) but they are not suitable to program postconditions and exception guarantees using this library (because those require capturing by reference, see __Postconditions__ and __Exception_Guarantees__), plus they introduce a copy of the captured value that might be too expensive in general and therefore not suitable for preconditions either. -] -* Code of the contract functions is separated from function body implementations (see __Separate_Body_Implementation__). [footnote Alternatively, on compilers that do not support C++11 lambda functions, [@http://www.boost.org/doc/libs/release/libs/local_function/doc/html/index.html Boost.LocalFunction] could be used to program the contract functors still within the function definitions (for example, see [@../../example/features/no_lambdas_local_func.cpp =no_lambda_local_func.cpp=]). In general, such a code is less verbose than the example shown in this section that uses contract functions programmed outside of the original function definitions (about 30% less lines of code) but the contract code is hard to read. Other libraries could also be used to program the contract functors without C++11 lambda functions (Boost.Lambda, Boost.Fusion, etc.) but again all these techniques will result in contract code either more verbose, or harder to read and maintain than the code that uses C++11 lambda functions. ] +* Contract functions (i.e., the `..._precondition`, `..._old`, and `..._postcondition` functions in the example below) can be programmed to fully enforce constant-correctness and other contract requirements at compile-time (see __Constant_Correctness__). +[footnote +If C++ allowed lambda functions to capture variables by constant reference (for example allowing a syntax like this `[const&] { ... }` and `[const& `[^['variable-name]]`] { ... }`, see [@https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/0UKQw9eo3N0]) also lambdas could be used to program contract functors that fully enforce __Constant_Correctness__ at compile-time. +Note that C++11 lambdas allow to capture variables by value (using `[=] { ... }` and `[`[^['variable-name]]`] { ... }`) and these value captures are `const` (unless the lambda is explicitly declared `mutable`) but they are not suitable to program postconditions and exception guarantees using this library (because those require capturing by reference, see __Postconditions__ and __Exception_Guarantees__), plus they introduce a copy of the captured value that might be too expensive in general and therefore not suitable for preconditions either. +] +* Code of the contract functions is separated from function body implementations (see __Separate_Body_Implementation__). However, not using C++11 lambda functions comes at the significant cost of having to manually program the extra contract functions and related boiler-plate code. -For example (see [@../../example/features/no_lambdas.hpp =no_lambdas.hpp=] and [@../../example/features/no_lambdas.cpp =no_lambdas.cpp=]): +For example, the header file (see [@../../example/features/no_lambdas.hpp =no_lambdas.hpp=]): [import ../example/features/no_lambdas.hpp] [no_lambdas_hpp] +And, the source file (see [@../../example/features/no_lambdas.cpp =no_lambdas.cpp=]): + [import ../example/features/no_lambdas.cpp] [no_lambdas_cpp] @@ -552,8 +556,8 @@ If programmers also want to fully enforce all contract programming constant-corr * Postcondition functions (i.e., the `..._postcondition` functions in the example above) should take their arguments by `const&`, and when they are member functions they should be either `static` or `const` functions. * Similarly, exception guarantee functions (not shown in the example above) should take their arguments by `const&`, and when they are member functions they should be either `static` or `const` functions. * Old value functions (i.e., the `..._old` functions in the example above) should take their arguments by `const&` a part from old value pointers that should be taken by `&` (so only old value pointers can be modified), and when they are member functions they should be either `static` or `const` functions. -* Constructor precondition, old value, and exception guarantee functions should be `static` (because there is no valid object `this` if the constructor body does not run successfully, see __Constructor_Calls__). -* Destructor postcondition functions should be `static` (because there is no valid object `this` after the destructor body runs successfully, but exception guarantee functions do not have to be `static` since the object `this` is still valid because the destructor body did not run successfully, see __Destructor_Calls__). +* For constructors: Precondition, old value, and exception guarantee functions should be `static` (because there is no valid object `this` if the constructor body does not run successfully, see __Constructor_Calls__). +* For destructors: Postcondition functions should be `static` (because there is no valid object `this` after the destructor body runs successfully, but exception guarantee functions do not have to be `static` since the object `this` is still valid because the destructor body did not run successfully, see __Destructor_Calls__). Note that the extra contract functions also allow to keep the contract code in the header file while all function bodies are implemented in a separate source file (including the constructor member initialization list, that could not be done with the techniques shown in __Separate_Body_Implementation__). [footnote @@ -562,7 +566,7 @@ As always with `bind`, `cref` and `ref` must be used to bind arguments by `const ] Also note that the contract functions can always be declared `private` if programmers need to exactly control the public members of the class (this was not done in this example only for brevity). -The authors think this library is most useful when used together with C++11 lambda functions. +The authors think this library is most useful when used together with C++11 lambda functions (because of the large amount of boiler-plate code required when C++11 lambdas are not used as also shown by the example above). [endsect] @@ -589,7 +593,7 @@ The [macroref BOOST_CONTRACT_MAX_ARGS] macro is named after `BOOST_FUNCTION_MAX_ These macro cannot be programmed manually but they are not variadic macros (so programmers should be able to use them on any C++ compiler with a sound support for SFINAE). [footnote *Rationale:* -These macros expand SFINAE-based introspection templates that are too complex to be programmed manually by users (that remains the case even if C++14 generic lambdas were to be used here). +These macros expand to SFINAE-based introspection template code that are too complex to be programmed manually by users (that remains the case even if C++14 generic lambdas were to be used here). On a related note, in theory using C++14 generic lambdas, the [macroref BOOST_CONTRACT_OVERRIDE] macro could be re-implemented in a way that can be expanded at function scope, instead of class scope (but there is not really a need to do that). ] The [macroref BOOST_CONTRACT_OVERRIDES] macro is a variadic macro instead but programmes can manually repeat the non-variadic macro [macroref BOOST_CONTRACT_OVERRIDE] for each overriding public function name on compilers that do not support variadic macros. @@ -598,38 +602,39 @@ The [macroref BOOST_CONTRACT_OVERRIDES] macro is a variadic macro instead but pr As shown in __Preconditions__, __Postconditions__, __Exception_Guarantees__, __Class_Invariants__, etc. this library provides the [macroref BOOST_CONTRACT_ASSERT] macro to assert contract conditions. This is not a variadic macro and programmers should be able to use it on all C++ compilers. -In any case, the invocation `BOOST_CONTRACT_ASSERT(cond)` expands to code equivalent to the following: +In any case, the invocation `BOOST_CONTRACT_ASSERT(`[^['cond]]`)` simply expands to code equivalent to the following: [footnote *Rationale:* There is no need for the code expanded by [macroref BOOST_CONTRACT_ASSERT] to also use C++11 `__func__`. -That is because `__func__` will always expand to the name of `operator()` of the functor used to program the contract assertions (e.g., of the lambda function) and it will not expand to the name of the actual function specifying the contract. +That is because `__func__` will always expand to the name `operator()` of the functor used to program the contract assertions (e.g., the internal name the compiler assigns to lambda functions) and it will not expand to the name of the actual function enclosing the contract declaration. ] - if(!(cond)) { + if(!(``[^['cond]]``)) { throw boost::contract::assertion_failure(__FILE__, __LINE__, - BOOST_PP_STRINGIZE(cond)); + BOOST_PP_STRINGIZE(``[^['cond]]``)); } In fact, this library considers any exception thrown from within preconditions, postconditions, exception guarantees, and class invariants as a contract failure and reports it calling the related contract failure handler ([funcref boost::contract::precondition_failure], etc.). If there is a need for it, programmers can always program contract assertions that throw specific user-defined exceptions as follow (see __Throw_on_Failures__): - if(!cond) throw exception_object; + if(!``[^['cond]]``) throw ``[^['exception-object]]``; However, using [macroref BOOST_CONTRACT_ASSERT] is convenient because it always allows this library to show an informative message in case of assertion failure containing the assertion code, file name, line number, etc. -The [macroref BOOST_CONTRACT_ASSERT_AUDIT] and [macroref BOOST_CONTRACT_ASSERT_AXIOM] macros are not variadic macros and programmers should be able to use them on all C++ compilers. -Their implementations are equivalent to the following: +As shown in __Assertion_Levels__, this library pre-defines [macroref BOOST_CONTRACT_ASSERT_AUDIT] and [macroref BOOST_CONTRACT_ASSERT_AXIOM] assertion levels. +These macros are not variadic macros and programmers should be able to use them on all C++ compilers. +In any case, their implementations are equivalent to the following: #ifdef BOOST_CONTRACT_AUDITS - #define BOOST_CONTRACT_ASSERT_AUDIT(cond) \ - BOOST_CONTRACT_ASSERT(cond) + #define BOOST_CONTRACT_ASSERT_AUDIT(``[^['cond]]``) \ + BOOST_CONTRACT_ASSERT(``[^['cond]]``) #else - #define BOOST_CONTRACT_ASSERT_AUDIT(cond) \ - BOOST_CONTRACT_ASSERT(true || (cond)) + #define BOOST_CONTRACT_ASSERT_AUDIT(``[^['cond]]``) \ + BOOST_CONTRACT_ASSERT(true || (``[^['cond]]``)) #endif - #define BOOST_CONTRACT_ASSERT_AXIOM(cond) \ - BOOST_CONTRACT_ASSERT(true || (cond)) + #define BOOST_CONTRACT_ASSERT_AXIOM(``[^['cond]]``) \ + BOOST_CONTRACT_ASSERT(true || (``[^['cond]]``)) [heading Base Types (Variadic)] @@ -654,7 +659,7 @@ For example (see [@../../example/features/old_no_macro.cpp =old_no_macro.cpp=]): [import ../example/features/old_no_macro.cpp] [old_no_macro] -The ternary operator `boost::contract::copy_old(v) ? size() : boost::contract::null_old()` must be used here to avoid evaluating and copying the old value expression `size()` when [funcref boost::contract::copy_old] returns `false` (because old values are not being copied when postcondition and exception guarantees checking is disabled at run-time, an overridden virtual function call is not checking postconditions or exception guarantees yet, etc.). +The ternary operator `boost::contract::copy_old(v) ? size() : boost::contract::null_old()` must be used here to avoid evaluating and copying the old value expression `size()` when [funcref boost::contract::copy_old] returns `false` (because old values are not being copied when postcondition and exception guarantee checking is disabled at run-time, an overridden virtual function call is not checking postconditions or exception guarantees yet, etc.). The enclosing [funcref boost::contract::make_old] copies the old value expression and creates an old value pointer. Otherwise, [funcref boost::contract::null_old] indicates that a null old value pointer should be created. diff --git a/example/features/move.cpp b/example/features/move.cpp index caa68f3b..de54d16a 100644 --- a/example/features/move.cpp +++ b/example/features/move.cpp @@ -22,7 +22,7 @@ class circular_buffer : } // Move constructor. - /* implicit */ circular_buffer(circular_buffer&& other) : + circular_buffer(circular_buffer&& other) : boost::contract::constructor_precondition([&] { BOOST_CONTRACT_ASSERT(!other.moved()); }) @@ -87,7 +87,7 @@ class circular_buffer : } // Copy constructor. - /* implicit */ circular_buffer(circular_buffer const& other) : + circular_buffer(circular_buffer const& other) : boost::contract::constructor_precondition([&] { BOOST_CONTRACT_ASSERT(!other.moved()); }) diff --git a/example/features/union.cpp b/example/features/union.cpp index fdbfe2ee..0681c774 100644 --- a/example/features/union.cpp +++ b/example/features/union.cpp @@ -28,7 +28,7 @@ union positive { explicit positive(int x) : d_(0) { // ...unions cannot have bases so constructor preconditions here. boost::contract::constructor_precondition pre([&] { - BOOST_CONTRACT_ASSERT(x >= 0); + BOOST_CONTRACT_ASSERT(x > 0); }); boost::contract::old_ptr old_instances = BOOST_CONTRACT_OLDOF(instances()); @@ -60,7 +60,7 @@ union positive { void get(int& x) const { boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { - BOOST_CONTRACT_ASSERT(x >= 0); + BOOST_CONTRACT_ASSERT(x > 0); }) ; @@ -84,7 +84,7 @@ union positive { explicit positive(double x) : d_(0) { // Unions cannot have bases so constructor preconditions here. boost::contract::constructor_precondition pre([&] { - BOOST_CONTRACT_ASSERT(x >= 0); + BOOST_CONTRACT_ASSERT(x > 0); }); boost::contract::old_ptr old_instances = BOOST_CONTRACT_OLDOF(instances()); @@ -102,7 +102,7 @@ union positive { void get(double& x) const { boost::contract::check c = boost::contract::public_function(this) .postcondition([&] { - BOOST_CONTRACT_ASSERT(x >= 0); + BOOST_CONTRACT_ASSERT(x > 0); }) ; diff --git a/include/boost/contract/core/config.hpp b/include/boost/contract/core/config.hpp index e33c2bff..c4e266ee 100644 --- a/include/boost/contract/core/config.hpp +++ b/include/boost/contract/core/config.hpp @@ -587,8 +587,8 @@ Configure this library compile-time and run-time behaviours. compilation from production code). @see @RefSect{tutorial.old_values, Old Values}, - @RefSect{advanced.old_value_copies_at_body, - Old Value Copies at Body}, + @RefSect{advanced.old_values_copied_at_body, + Old Values Copied at Body}, @RefSect{extras.disable_contract_compilation__macro_interface_, Disable Contract Compilation} */ diff --git a/include/boost/contract/core/exception.hpp b/include/boost/contract/core/exception.hpp index 2a1d144d..642cc090 100644 --- a/include/boost/contract/core/exception.hpp +++ b/include/boost/contract/core/exception.hpp @@ -715,7 +715,7 @@ Set a new failure handler and returns it. concatenating function calls). @see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, - @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body} + @RefSect{advanced.old_values_copied_at_body, Old Values Copied at Body} */ inline from_failure_handler const& set_old_failure(from_failure_handler const& f) /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { @@ -736,7 +736,7 @@ This is often called only internally by this library. @return A copy of the failure handler currently set. @see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, - @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body} + @RefSect{advanced.old_values_copied_at_body, Old Values Copied at Body} */ inline from_failure_handler get_old_failure() /** @cond */ BOOST_NOEXCEPT_OR_NOTHROW /** @endcond */ { @@ -761,7 +761,7 @@ This is often called only internally by this library. throw exceptions instead of terminating the program). @see @RefSect{advanced.throw_on_failures__and__noexcept__, Throw on Failure}, - @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body} + @RefSect{advanced.old_values_copied_at_body, Old Value Copied at Body} */ inline void old_failure(from where) /* can throw */ { #ifndef BOOST_CONTRACT_DISABLE_THREADS diff --git a/include/boost/contract/core/specify.hpp b/include/boost/contract/core/specify.hpp index 758ec69c..174c0643 100644 --- a/include/boost/contract/core/specify.hpp +++ b/include/boost/contract/core/specify.hpp @@ -364,7 +364,7 @@ This object is internally constructed by this library when users specify contracts calling @RefFunc{boost::contract::function} and similar functions (that is why this class does not have a public constructor). -@see @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}, +@see @RefSect{advanced.old_values_copied_at_body, Old Values Copied at Body}, @RefSect{tutorial.postconditions, Postconditions}, @RefSect{tutorial.exception_guarantees, Exception Guarantees} @@ -392,7 +392,7 @@ class specify_old_postcondition_except { // Privately copyable (as *). It should often be sufficient to initialize old value pointers as soon as they are declared, without using this function (see - @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}). + @RefSect{advanced.old_values_copied_at_body, Old Values Copied at Body}). @param f Nullary functor called by this library @c f() to assign old value copies just before the body is executed but after entry @@ -510,7 +510,7 @@ contracts calling @RefFunc{boost::contract::function} and similar functions (that is why this class does not have a public constructor). @see @RefSect{tutorial.preconditions, Preconditions}, - @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}, + @RefSect{advanced.old_values_copied_at_body, Old Values Copied at Body}, @RefSect{tutorial.postconditions, Postconditions}, @RefSect{tutorial.exception_guarantees, Exception Guarantees} @@ -565,7 +565,7 @@ class specify_precondition_old_postcondition_except { // Priv. copyable (as *). It should often be sufficient to initialize old value pointers as soon as they are declared, without using this function (see - @RefSect{advanced.old_value_copies_at_body, Old Value Copies at Body}). + @RefSect{advanced.old_values_copied_at_body, Old Values Copied at Body}). @param f Nullary functor called by this library @c f() to assign old value copies just before the body is executed but after entry diff --git a/include/boost/contract_macro.hpp b/include/boost/contract_macro.hpp index 8bfa7c84..98fb4580 100644 --- a/include/boost/contract_macro.hpp +++ b/include/boost/contract_macro.hpp @@ -197,8 +197,8 @@ Disable Contract Compilation}). @see @RefSect{extras.disable_contract_compilation__macro_interface_, Disable Contract Compilation}, - @RefSect{advanced.old_value_copies_at_body, - Old Value Copies at Body} + @RefSect{advanced.old_values_copied_at_body, + Old Values Copied at Body} */ #define BOOST_CONTRACT_OLD(...)