Я столкнулся с функцией экземпляра класса, которой нужно было временно изменить переменную экземпляра класса, а затем восстановить ее после завершения функции. В функции повсюду были операторы возврата, и перед каждым возвратом был оператор восстановления. Мне это показалось грязным, не говоря уже о страшном, когда возникает исключение.
В качестве улучшения я придумал это обобщение, используя определение внутреннего класса. Вот пример программы-драйвера (восстановитель класса).
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):
a in: 0 b in: 0 c in: 1 d in: 1 deepest d end: 1 c end: 1 b inner end: 1 b end: 0 a end: 0
Это то, что я ожидаю в "b end".
Я чувствовал, что определение восстановителя класса внутри класса Unwind помогает предотвратить неправильное использование.
Мой вопрос: есть ли общий и более безопасный способ сделать это? Меня беспокоят жизненные проблемы.
Изменить: предположим, что в стеке нет потоков, а есть «нисходящие» методы, которые изменяют поведение на основе этого флага b_active_.