Существуют ли установленные шаблоны для проверки инвариантов классов в C++?проверка инвариантов в C++
В идеале, инварианты будут автоматически проверяться в начале и в конце каждой публичной функции-члена. Насколько я знаю, C с классами предоставлял специальные функции before
и after
, но, к сожалению, дизайн по контракту в то время был не очень популярен, и никто, кроме Бьярна, не использовал эту функцию, поэтому он удалил ее.
Конечно, ручная установка check_invariants()
вызовов в начале и в конце каждой функции открытого члена является утомительной и подверженной ошибкам. Так RAII этого оружия выбора для борьбы с исключениями, я придумал следующую схему определения неизменности проверки в качестве первого локального переменного, а инвариантность проверка проверяет инварианты как на строительстве и уничтожения время:
template <typename T>
class invariants_checker
{
const T* p;
public:
invariants_checker(const T* p) : p(p)
{
p->check_invariants();
}
~invariants_checker()
{
p->check_invariants();
}
};
void Foo::bar()
{
// class invariants checked by construction of _
invariants_checker<Foo> _(this);
// ... mutate the object
// class invariants checked by destruction of _
}
Вопрос № 0: Я полагаю, что нет способа объявить неназванную локальную переменную? :)
Нам еще нужно позвонить check_invariants()
вручную в конце конструктора Foo
и в начале деструктора Foo
. Однако многие тела конструктора и тела деструктора пустые. В таком случае мы могли бы использовать invariants_checker
в качестве последнего члена?
#include <string>
#include <stdexcept>
class Foo
{
std::string str;
std::string::size_type cached_length;
invariants_checker<Foo> _;
public:
Foo(const std::string& str)
: str(str), cached_length(str.length()), _(this) {}
void check_invariants() const
{
if (str.length() != cached_length)
throw std::logic_error("wrong cached length");
}
// ...
};
Вопрос № 1: Справедливо ли передать this
в invariants_checker
конструктор, который сразу вызывает check_invariants
через этот указатель, даже несмотря на то, Foo
объект находится на стадии строительства?
Вопрос №2: Вы видите какие-либо другие проблемы с этим подходом? Можете ли вы его улучшить?
Вопрос № 3: Этот подход является новым или общеизвестным? Есть ли лучшие решения?
Вы не можете использовать 'this' в списке инициализаторов. Вы можете использовать его, однако, в теле конструктора. – Benoit
@Benoit: Что вы имеете в виду с * не может *? Это строго запрещено? Вызывает ли это неопределенное поведение? – fredoverflow
Thorsten Ottesen (я думаю, что это было) было предложение по дизайну по контракту. В первом раунде он не вышел из-под контроля, из-за трудности принятия решения о внутреннем и внешнем вызове (вы можете временно нарушить инвариант для внутреннего вызова). Но он все еще может появиться. Не знаю, активно ли он работает. –