1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// Copyright (C) 2008-2018 Lorenzo Caminiti
// Distributed under the Boost Software License, Version 1.0 (see accompanying
// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
#include <boost/contract.hpp>
#include <iostream>
#include <cstring>
#include <cassert>
//[throw_on_failure_class_begin
struct too_large_error {};
template<unsigned MaxSize>
class cstring
#define BASES private boost::contract::constructor_precondition<cstring< \
MaxSize> >
: BASES
{
//]
public:
typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
#undef BASES
//[throw_on_failure_ctor
public:
/* implicit */ cstring(char const* chars) :
boost::contract::constructor_precondition<cstring>([&] {
BOOST_CONTRACT_ASSERT(chars); // Throw `assertion_failure`.
// Or, throw user-defined exception.
if(std::strlen(chars) > MaxSize) throw too_large_error();
})
{
//]
boost::contract::check c = boost::contract::constructor(this)
.postcondition([&] {
BOOST_CONTRACT_ASSERT(size() == std::strlen(chars));
})
;
size_ = std::strlen(chars);
for(unsigned i = 0; i < size_; ++i) chars_[i] = chars[i];
chars_[size_] = '\0';
}
//[throw_on_failure_dtor
public:
void invariant() const {
if(size() > MaxSize) throw too_large_error(); // Throw user-defined ex.
BOOST_CONTRACT_ASSERT(chars_); // Or, throw `assertion_failure`.
BOOST_CONTRACT_ASSERT(chars_[size()] == '\0');
}
~cstring() noexcept { // Exception specifiers apply to contract code.
// Check invariants.
boost::contract::check c = boost::contract::destructor(this);
}
//]
unsigned size() const {
// Check invariants.
boost::contract::check c = boost::contract::public_function(this);
return size_;
}
private:
char chars_[MaxSize + 1];
unsigned size_;
//[throw_on_failure_class_end
/* ... */
};
//]
void bad_throwing_handler() { // For docs only (not actually used here).
//[throw_on_failure_bad_handler
/* ... */
// Warning... might cause destructors to throw (unless declared noexcept).
boost::contract::set_invariant_failure(
[] (boost::contract::from) {
throw; // Throw no matter if from destructor, etc.
}
);
/* ... */
//]
}
//[throw_on_failure_handlers
int main() {
boost::contract::set_precondition_failure(
boost::contract::set_postcondition_failure(
boost::contract::set_invariant_failure(
boost::contract::set_old_failure(
[] (boost::contract::from where) {
if(where == boost::contract::from_destructor) {
// Shall not throw from C++ destructors.
std::clog << "ignored destructor contract failure" << std::endl;
} else throw; // Re-throw (assertion_failure, user-defined, etc.).
}
))));
boost::contract::set_except_failure(
[] (boost::contract::from) {
// Already an active exception so shall not throw another...
std::clog << "ignored exception guarantee failure" << std::endl;
}
);
boost::contract::set_check_failure(
[] {
// But now CHECK shall not be used in destructor implementations.
throw; // Re-throw (assertion_failure, user-defined, etc.).
}
);
/* ... */
//]
{
cstring<3> s("abc");
assert(s.size() == 3);
}
#ifndef BOOST_CONTRACT_NO_PRECONDITIONS
// These failures properly handled only when preconditions checked.
try {
char* c = 0;
cstring<3> s(c);
assert(false);
} catch(boost::contract::assertion_failure const& error) {
// OK (expected).
std::clog << "ignored: " << error.what() << std::endl;
} catch(...) { assert(false); }
try {
cstring<3> s("abcd");
assert(false);
} catch(too_large_error const&) {} // OK (expected).
catch(...) { assert(false); }
#endif
return 0;
}
|