C++のクラス不変式を調べるための確立されたパターンはありますか?C++のインバリアントのチェック
不変式は理想的には、各パブリックメンバー関数の最初と最後に自動的にチェックされます。私が知る限り、クラスCは特別なbefore
とafter
のメンバー関数を提供しましたが、残念なことに、契約によるデザインは当時はあまり人気がなく、Bjarne以外の誰もその機能を使用しなかったので、彼はそれを削除しました。
もちろん、各パブリックメンバー関数の最初と最後に手動で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:名前のないローカル変数を宣言する方法がないと思いますか? :)
Foo
コンストラクタの最後とFoo
デストラクタの先頭に手動でcheck_invariants()
を呼び出す必要があります。しかし、多くのコンストラクタ本体とデストラクタ本体は空です。その場合、最後のメンバーとして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:それはすぐにFoo
オブジェクトがまだ建設中であっても、そのポインタ経由check_invariants
を呼び出しinvariants_checker
コンストラクタにthis
を渡すために有効ですか?
質問#2:この方法に他の問題はありますか?あなたはそれを改善できますか?
質問#3:このアプローチは新しいかよく知られていますか?より良いソリューションがありますか?
イニシャライザのリストで 'this'を使用することはできません。あなたはコンストラクタの本体でそれを使うことができます。 – Benoit
@Benoit:*とはどういう意味ですか?それは厳格に禁止されていますか?それは未定義の振る舞いを引き起こしますか? – fredoverflow
Thorsten Ottesen(私はそうだったと思う)はDesign by Contractの提案をしていた。最初のラウンドでは、内部のものと外部のものを決めるのが難しいため(彼らは内部呼び出しのために不変のものを一時的に破ることができます)、地面から降りませんでした。しかしそれはまだ現れるかもしれません。それが積極的に働いているかどうかはわかりません。 –