스택을 사용하여 멤버 변수를 원래 값으로 재설정하는 일반적인 방법?

StackOverflow https://stackoverflow.com/questions/207965

  •  03-07-2019
  •  | 
  •  

문제

클래스 인스턴스 변수를 일시적으로 변경 해야하는 클래스 인스턴스 기능을 발견 한 다음 함수가 완료되면 복원합니다. 이 기능에는 모든 곳에서 반환 진술이 있었고, 각 반환 전에 복원 진술이있었습니다. 예외가 발생했을 때 무섭지 않은 것은 나에게 지저분 해 보였다.

개선으로서 나는 내부 클래스 정의를 사용 하여이 일반화를 생각해 냈습니다. 다음은 샘플 드라이버 프로그램 (클래스 복원 자)입니다.

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top