스택을 사용하여 멤버 변수를 원래 값으로 재설정하는 일반적인 방법?
문제
클래스 인스턴스 변수를 일시적으로 변경 해야하는 클래스 인스턴스 기능을 발견 한 다음 함수가 완료되면 복원합니다. 이 기능에는 모든 곳에서 반환 진술이 있었고, 각 반환 전에 복원 진술이있었습니다. 예외가 발생했을 때 무섭지 않은 것은 나에게 지저분 해 보였다.
개선으로서 나는 내부 클래스 정의를 사용 하여이 일반화를 생각해 냈습니다. 다음은 샘플 드라이버 프로그램 (클래스 복원 자)입니다.
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"에서 기대하는 것입니다.
클래스의 수업 시간 동안 클래스 복원자를 정의하면 오용을 방해하는 데 도움이된다고 생각했습니다.
내 질문은, 이것을하는 일반적이고 안전한 방법이 있습니까? 평생 문제가 걱정됩니다.
편집 :이 b_active_ 플래그를 기반으로 동작을 변경하는 스택에 스레드가 없지만 "다운 스트림"메소드가 없다고 가정하십시오.
해결책 4
의견을 바탕으로 샘플을 조금 더 수정하고 질문을 편집하는 대신 커뮤니티 위키 답변으로 배치했습니다.
/// 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
다른 팁
나는 Adam Pierce에 동의하고 또한 당신이 포인터보다 참조를 선호해야한다고 생각합니다.
template<typename T>
class restorer {
T& ref_;
T save_;
public:
restorer(T& perm) : ref_(perm), save_(ref_) {};
~restorer() { ref_ = save_; }
};
복원 템플릿이 마음에 들지만 템플릿을 Unwind 클래스 외부 또는 별도의 헤더 파일에 넣어 향후 다른 클래스에서 재사용 할 수있을 것입니다. 그것은 또한 그것을 조금 더 읽기 쉽게 만들 것입니다.
이것이 내가 그렇게하는 방법입니다. 이 방법으로 함수가 어떤 이유로 던지거나 일찍 돌아 오면 복원기 객체가 파괴되고 변수가 원래 값으로 재설정됩니다. 문제는 실제로 기능이 반환 될 때 되돌리는 변수가 있어야하는 이유는 무엇입니까? 객체가 하나 이상의 스레드에서 사용됩니까?
Quantumpete