クラスインスタンス変数を一時的に変更し、関数が完了したときにそれを復元する必要があるクラスインスタンス関数に出くわしました。関数にはあらゆる場所に return ステートメントがあり、それぞれの return の前に復元ステートメントがありました。例外がスローされたときの恐怖は言うまでもなく、それは私には面倒に思えました。
改善として、内部クラス定義を使用してこの一般化を思いつきました。サンプルのドライバ プログラム (クラス復元プログラム) を次に示します。
class Unwind {
private:
bool b_active_; ///< the thing I want to be restored
template<typename T>
class restorer {
T* ref_;
T save_;
public:
restorer(T* perm) : ref_(perm), save_(*ref_) {};
~restorer() { *ref_ = save_; }
};
public:
Unwind() : b_active_(false) {};
void a() { out("a in"); b(); out("a end"); }
void b() {
out("b in");
{
restorer<bool> trust_in_the_stack(&b_active_); // "restorer" created on the stack
b_active_ = true; // change b_active_ only while "within" b()
c();
out("b inner end");
}
out("b end");
}
void c() { out("c in"); d(); out("c end"); }
void d() { out("d in"); cout << "deepest" << endl; out("d end"); }
void out(const std::string& msg) {
std::cout << msg << ": " << b_active_ << std::endl;
}
};
int main() { Unwind u; u.a(); return 0; }
g++ 4.2.3 (-Wall) を使用した出力は次のとおりです。
で: 0 で: 0 中: 1 中: 1 最も深い エンドエンド: 1 cエンド:1 b内端:1 bエンド:0 終了: 0
これが「bエンド」に期待するものです。
クラス Unwind 内でクラス復元子を定義すると、誤用を思いとどまらせるのに役立つと感じました。
私の質問は、これを行うための一般的で安全な方法はありますか? 一生の問題で悩んでいます。
編集: スレッドはなく、この b_active_ フラグに基づいて動作を変更するスタック上の「ダウンストリーム」メソッドがあると想定してください。