2013-07-23 34 views
6

也許我是在想這一點,但考慮下面的例子:RAII對象恢復以前的值

bool some_state = false; 

// ... later ... 

some_state = true; 
do_something(); 
some_state = false; 

現在想象一下,do_something()可以拋出。我們不會將some_state設置回false。什麼是好的是有某種是推動基於餘地記住以前的值/自動彈出堆棧:

{ 
    scoped_restore res(some_state, true); // This sets some_state to true and remembers previous value (false) 
    do_something(); 
} // At this point, res is destroyed and sets some_state back to false (previous value) 

確實提升有這樣的事?我當然可以寫自己的對象,但是我想確保我不會首先重新發明輪子。我在MSVC上使用C++ 03,所以我不能使用任何奇特的新的C++ 11:(

+0

它,而不是語言本身更編碼風格的問題。只需使用'try/catch' ... – billz

+3

@billz try/catch用於異常處理,不是正常的,預期的邏輯。投擲也有性能影響。不可接受的解決方案。 RAII不是一種編碼風格偏好,它是一種設計模式。 –

+2

還有[Boost.ScopeExit](http://www.boost.org/doc/libs/1_39_0/libs/scope_exit/doc/html/index.html),但我不確定是否適合。用法:'BOOST_SCOPE_EXIT(some_state = true);' –

回答

0

你正在吠叫正確的樹Bjarne Stroustrup強烈建議RAII進行異常處理在最新版的C++編程語言(第4版)中,他完全概述了他在第13章異常處理中推薦的方法。

要替換整個章節很難,所以首先關閉,我建議你只是閱讀這一章,但是,基本的想法是使用合成,並讓構造函數保護資源。因此,如果你有類A保護可能每個拋出的3個資源(perh aps一些內存),而是讓子對象在其構造函數中保護每個(不是A的構造函數)。關鍵的一點是,如果允許構造函數完成,就會保證(通過語言)析構函數將被調用。因此,在頂層的構造函數初始化子對象是這樣的:

class B{ 

    public: 

     B(int n) 
     { 
      //allocate memory (may throw) 
     } 

     void *secured_memory; 

     ~B(){ 
      //release memory   
     } 

} 


class A{ 

    public: 

     A(int n) 
      :b{n}, c{n}, d{n} 
     { 
      //will not complete if B, C or D throws 
      //but because the constructors of B and C completed 
      //their destructors will be invoked if D throws   
     } 

     B b; 
     C c; 
     D d; 

} 

試想一下,C類和d存在,他們是如此的結構類似於B.在你上面的例子,some_state將通過固定類似B,C或D.

另一個關鍵點在這裏。您應該只在每個子對象的類中確保一個資源。這樣,資源被獲取並允許構造函數退出(從而確保析構函數被調用,這將安全地釋放資源),或者拋出(因此不會獲取資源)。