Allgemein Art und Weise eine Membervariable auf den ursprünglichen Wert mit dem Stapel zurücksetzen?

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

  •  03-07-2019
  •  | 
  •  

Frage

Ich stieß auf eine Klasseninstanz Funktion, die vorübergehend benötigt, um eine Klasseninstanzvariable zu ändern, und dann wiederherstellen, wenn die Funktion beendet. Die Funktion hatte Aussagen alle über den Ort zurückzukehren, und vor jeder Rückkehr eine Wiederherstellung der Anweisung war. Das schien mir unordentlich, nicht beängstigend zu erwähnen, wenn eine Ausnahme ausgelöst wird.

Als Verbesserung ich mit dieser Verallgemeinerung einer inneren Klassendefinition unter Verwendung kam. Hier ist ein Beispiel Treiberprogramm (Klasse Restaurator).

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; }

Die Ausgabe mit g ++ 4.2.3 (-Wall) war:

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

Das ist, was ich bei "b end" erwartet.

Ich fühlte, dass innerhalb der Klasse, die Klasse Restaurator definiert Unwind Missbrauch entmutigen kann.

Meine Frage ist, gibt es einen allgemeinen und sicheren Weg, dies zu tun? Ich mache mir Sorgen um Lebenszeit Probleme.

Edit:. Gehen Sie davon aus, dass es keine Themen sind, aber „stromabwärts“ Methoden auf dem Stack, das Verhalten zu ändern, basierend auf dieser b_active_ Flag

War es hilfreich?

Lösung 4

überarbeitete ich die Probe ein bisschen mehr auf den Kommentaren basiert und als Community Wiki Antwort statt der Bearbeitung der Frage gestellt.

/// 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

Andere Tipps

ich mit Adam Pierce einverstanden und denke auch, dass Sie Referenzen über Zeiger bevorzugen sollten:

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

Ich mag die Restorer-Vorlage, aber ich würde wahrscheinlich die Vorlage außerhalb der Unwind Klasse oder sogar in einer separaten Header-Datei eingeben, damit sie von anderen Klassen in der Zukunft wieder verwendet werden können. Das wäre es auch ein wenig besser lesbar machen.

Dies ist, wie ich es auch tun würde. Auf diese Weise, wenn die Funktion auslöst, oder kehrt vorzeitig aus irgendeinem Grunde, wird Ihr Restorer-Objekt zerstört werden und die Variable wieder auf den ursprünglichen Wert zurück. Die Frage ist wirklich, warum brauchen Sie eine Variable haben, die, wenn die Funktion zurückkehrt zurückgekehrt ist? Ist das Objekt von mehr als einem Thread verwendet?

QuantumPete

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top