2008-10-16 16 views
2

我遇到了需要臨時更改類實例變量的類實例函數,然後在函數完成時將其恢復。該函數在所有地方都有return語句,並且在每次返回之前都有一個恢復語句。這對我來說似乎很混亂,更不用說提出異常時可怕了。使用堆棧將成員變量重置爲原始值的一般方法?

作爲一種改進,我想出了使用內部類定義的泛化。這是一個示例驅動程序(類恢復器)。

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

使用克++ 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端」。

我覺得在類Unwind中定義類恢復器有助於防止濫用。

我的問題是,是否有一個通用和安全的方法來做到這一點? 我很擔心有生之年的問題。

編輯:請假定堆棧上沒有線程,而是根據此b_active_標誌更改行爲的「下游」方法。

+0

我認爲最好用save _(* perm)替換初始化列表中的save _(* ref_)。保存_(* ref_)可能會咬你有一天,當有人改變你的課堂上的聲明順序。 – 2008-10-17 01:24:02

回答

0

我修改基於註釋的樣本多一點,並放在爲社區維基回答,而不是編輯題。

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

這就是我將如何做到這一點。這樣,如果函數拋出或由於某種原因返回提前,則您的Restorer對象將被銷燬並且該變量重置爲原始值。真正的問題是,爲什麼你需要有一個變量在函數返回時被還原?該對象是否使用多個線程?

QuantumPete

3

我喜歡的恢復模板,但我可能會把模板開卷類外,甚至在一個單獨的頭文件,以便它可以在未來其他類重用。這也會使它更具可讀性。

6

我同意亞當皮爾斯也認爲你應該更喜歡指針引用:

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