Есть ли какая-либо библиотека, которая помогает реализовать проект по принципу контракта в приложении С++?
В частности, я ищу библиотеку, которая обеспечивает использование принципа, что-то вроде this.
Есть ли какая-либо библиотека, которая помогает реализовать проект по принципу контракта в приложении С++?
В частности, я ищу библиотеку, которая обеспечивает использование принципа, что-то вроде this.
Я следил за учениями следующих статей:
То, что я в конечном счете применял, было в значительной степени подходом Samek. Простое создание макросов для REQUIRE, ENSURE, CHECK и INVARIANT (на основе существующего макроса assert
) было очень полезным. Конечно, это не так хорошо, как поддержка родного языка, но в любом случае, это позволяет вам получить большую часть практической ценности от этой техники.
Что касается библиотек, я не думаю, что он платит их, потому что одним из важных значений механизма утверждения является его простота.
За разницу между кодом отладки и производством см. Когда должны оставаться утверждения в производственном коде?.
Простейшая?
Утвердить утверждения в начале вашей функции, чтобы проверить ваши требования. Утвердить утверждения в конце вашей функции, чтобы проверить ваши результаты.
Да, это грубо, его не большая система, но его простота делает его универсальным и портативным.
Некоторые шаблоны проектирования, такие как не виртуальный интерфейс, делают естественным писать пре/пост-условия для данного метода:
#include <cassert>
class Car {
virtual bool engine_running_impl() = 0;
virtual void stop_impl() = 0;
virtual void start_impl() = 0;
public:
bool engine_running() {
return engine_running_impl();
}
void stop() {
assert(engine_running());
stop_impl();
assert(! engine_running());
}
void start()
{
assert(! engine_running());
start_impl();
assert(engine_running());
}
}
class CarImpl : public Car {
bool engine_running_impl() {
/* ... */
}
void stop_impl() {
/* ... */
}
void start_impl() {
/* ... */
}
}
Если вы не против использования функций С++ 0x, вы можете реализовать предварительные условия и постусловия с помощью lambdas и RAII.
Простой пример постусловия:
struct __call_on_destructor {
std::tr1::function<void()> _function;
template<class Func> inline __call_on_destructor(Func func) {
_function = func;
}
inline ~__call_on_destructor() {
_function();
}
};
#define on_scope_exit(function) \
__call_on_destructor PP_UNIQUE_LABEL(on_exit) (function)
#define ensures(expression) \
on_scope_exit([&] () { assert(expression); })
Аналогично, вы можете реализовать предварительные условия и инварианты. Код был взят из чрезвычайно простой С++ 0x Contracts library.
Попробуйте следующее: Contract ++. Он был принят к Boost (но еще не доставляется).
У меня есть заголовок litle С++ с требованиями, страхованием и инвариантами. Он имеет менее 400 мест и должен удовлетворять вашим потребностям. Вы можете найти его под dhc.hpp Он сообщает об ошибках полезным способом и может быть скомпилирован через define.
#include <dbc.hpp>
class InvarTest {
public:
int a = 0;
int b = 9;
INVARIANT_BEGIN
Inv(RN(0,a,32));
Inv(RN(0,b,10));
INVARIANT_END
inline void changeMethod() {
Invariant(); // this runs the invariant block at the beginning and end of the method
a = 33;
}
};
int testFunc(int a, double d, int* ip) {
// RN = a in range 0 to 10, NaN = not a number, NN = not null
Rqr(RN(0,a,10), NaN(d), RN(0.0,d,1.0), NN(ip));
// Enr return the passed value
return Esr(RN(0.0,a+d,20.3));
}
void testFunc2(std::vector<int>& a, std::shared_ptr<int> sp) {
Rqr( SB(a,0), TE(a.size() % 12 == 0), NN(sp));
}
Использовать стандартный ASSERT/Q_ASSERT, но остерегайтесь "недействительных" утверждений, особенно если вы оставите такую диагностику во внешнем тестировании (создайте без NDEBUG).
Небольшая история о реализации DBC (с использованием утверждений) в проекте С++ и политике "отладка всегда включена".
Мы использовали стандартные инструменты (ASSERT()/Q_ASSERT()) в качестве реализации DBC, пока мы не достигли следующей ситуации в тестировании интеграции: наша последняя сборка всегда терпела неудачу сразу после запуска. Было не очень профессионально выпускать такую версию (после недели внутренних усилий по обеспечению качества).
Как появилась проблема?
В результате плохой разработчик был обвинен в этой ошибке (очевидно, без этого ASSERT не было бы сбоя), и нам пришлось выпустить исправление, чтобы продолжить интеграционные тесты.
Прежде всего: мне нужны утверждения, включенные в тестах интеграции для отслеживания неудачных условий (чем больше утверждений, тем лучше), с другой стороны, я не хочу, чтобы разработчики боятся, что некоторые "дополнительные" ASSERT будут разбивать полный стек программного обеспечения.
Я нашел, возможно, интересное разрешение на основе С++ для этой проблемы: слабые asserions. Идея не останавливать цельное приложение при неудачном завершении, но записывать stacktrace для последующего анализа и продолжать. Мы можем проверить столько ожиданий, сколько пожелаем, без страха перед сбоем, и мы получим обратную связь (stacktraces) от интеграции. Один прогон процесса может обеспечить множество неудачных утверждений для анализа вместо одного (потому что не вызывается прерывание()).
Реализация этой идеи (с использованием некоторой магии LD_PRELOAD) кратко описана здесь: http://blog.aplikacja.info/2011/10/assert-to-abort-or-not-to-abort-thats-the-question/