A common way to reset a member variable to its original value using the stack?

I came across a class instance function that required to temporarily change the class instance variable and then restore it when the function exited. The function had return statements all over the place, and an instruction returned before each return. It seemed messy to me, not to mention that it's scary when an exception occurs.

As an improvement, I came up with this generalization using the definition of an inner class. Here is an example of a program driver (restorer class).

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; ua(); return 0; } 

The output using g ++ 4.2.3 (-Wall) was:

  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

This is what I expect at the end of "b".

I felt that defining a class restorer inside an Unwind class helps to discard misuse.

My question is: is there a general and safe way to do this? I am worried about life issues.

Edit: Assume that there are no threads on the stack, but "downstream" methods that change behavior based on this flag b_active_.

+2
source share
4 answers

I revised the sample a bit more, based on the comments, and fit as a response from the Wiki community instead of editing the question.

 /// c++ code sample #ifndef UTIL_RESTORER_HPP #define UTIL_RESTORER_HPP namespace Utility { /// A Restorer instance ("inst") uses the stack to restore a saved /// value to the named variable when the instance "inst" goes out of /// scope. /// /// Restorer is designed to be an auto variable, not allocated on any /// other memory resource like a heap or in-place. template<typename T> class restorer { T& ref_; T save_; public: restorer(T& perm) : ref_(perm), save_(perm) {} ~restorer() { ref_ = save_; } }; }//NAMESPACE #endif//UTIL_RESTORER_HPP 
0
source

I agree with Adam Pierce, and I also think that you should prefer pointers to links:

 template<typename T> class restorer { T& ref_; T save_; public: restorer(T& perm) : ref_(perm), save_(ref_) {}; ~restorer() { ref_ = save_; } }; 
+6
source

I like the restorer template, but I would probably put the template outside of the Unwind class or even in a separate header file so that it can be reused by other classes in the future. It would also make it more readable.

+3
source

This is how I do it. Thus, if a function throws or returns early for any reason, the Restorer object will be destroyed, and the reset variable will be destroyed. The question is, why do you need the variable returned when the function returns? Is an object more than one thread?

Quantumpete

0
source

Source: https://habr.com/ru/post/1480123/


All Articles