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:名前のないローカル変数を宣言する方法はないと思いますか?:)
コンストラクタの最後とデストラクタの最初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:このアプローチは新しいものですか、それともよく知られていますか?より良い解決策はありますか?