2015-01-02 73 views
1

我試圖創建一個「大多不變」的類,它允許客戶端如果需要破壞不變量,但僅當它們在離開範圍之前修復它發生這種糟糕的事情。從守衛類析構函數拋出異常導致std :: terminate

以下是涉及的兩個類。這與範圍守衛相似。更多細節,評論和ideone的小測試。

http://ideone.com/dMCHVU

class HCAccessor; 

class HasConditions 
{ 
    // class "mostly-invariant" 
    // 7 < payload_ <42 
    int payload_; 

    bool valid() const 
    { 
     if (!(7 < payload_) || !(payload_ < 42)) 
      return false; 
     else 
      return true; 
    } 

public: 
    HasConditions(const int payload) 
     : payload_(payload) 
    { 
     if (!valid()) 
     { 
      throw std::runtime_error("can't construct"); 
     } 
    } 

    friend class HCAccessor; 
}; 

class HCAccessor 
{ 
    HasConditions& hc_; 

public: 
    HCAccessor(HasConditions& hc) 
     : hc_(hc) 
    {} 

    HCAccessor(HCAccessor& other) 
     : hc_(other.hc_) 
    {} 

    ~HCAccessor() 
    { 
     if (!hc_.valid()) 
     { 
      throw std::runtime_error("you broke it!"); 
     } 
    } 

    void payload(const int newval) 
    { 
     hc_.payload_ = newval; 
    } 

    int payload() const 
    { 
     return hc_.payload_; 
    } 
}; 

當「大多是不變的」被打破,然後固定的代碼似乎工作。當「大多不變」仍然被打破,~HCAccessor()拋出,std::terminate被調用,我不知道爲什麼。導致std::terminate呼叫的異常的原因似乎都不合適。

http://en.cppreference.com/w/cpp/error/terminate

至於我可以告訴只有一個異常被拋出,然後立即std::terminate被調用。

爲什麼會發生這種情況,我該如何解決?

+0

不要[在析構函數中拋出異常](http://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor)。 –

+0

除了在析構函數中拋出異常是不好的,你實際上是在試圖捕獲異常嗎?你如何處理'HCAccessor'類的臨時對象?還是你在任何地方通過價值傳遞它? –

回答

3

C++ 11中的析構函數默認爲noexcept。如果你真的想這樣做,你有noexcept(false)申報HCAccessor的析構函數:

~HCAccessor() noexcept(false) { 

或老式拋列表:

~HCAccessor() throw(std::runtime_error) { 

(榮譽給普拉丹爲noexcept(false)語法我以前沒有見過,這不是我們經常需要的東西,我想)。

但是,這樣做幾乎肯定是一個壞主意™。飛行異常會導致在堆棧展開時調用析構函數,並且如果您有導致異常的析構函數,您最終會發現自己試圖同時拋出幾個異常。哪個爆炸。

如果HCAccessor的實例沒有管理任何資源,它在清理時沒有任何操作,而析構函數是一個nop。我不明白這是如何拋出異常的原因 - 只要保留即可。

+0

我一直在想這個,如果拋出一個無關的異常並且'HasConditions'也是無效的,那麼你實際上一次有兩個問題,它不僅僅是這個構造的一個神器。有沒有辦法處理這個問題? – Praxeolitic

+0

不是。你只需要設計你的類,使得無效對象不會發生,或者無效對象的銷燬不會導致問題。後者通常不是很難做到。 @Pradhan:唉,那有時候是這樣。如果你不介意的話,我會公然爲這個邪惡的案件竊取更好的語法。 – Wintermute

2

的C++ 11標準的12.4.3

析構函數的聲明不具有一個異常規範被隱式地認爲具有 相同異常規範作爲隱式宣言。

15.4.14

如果˚F是繼承構造函數或隱式聲明的默認構造函數,複製 構造,移動構造函數,析構函數,拷貝賦值運算符,或移動賦值運算符,其隱含的 異常規範指定type-id T當且僅當T被例外規範允許時 直接調用的函數f的隱式定義; ˚F允許所有的異常,如果任何功能直接 所調用允許所有的異常,並˚F異常規範noexcept(真)如果每個功能直接 所調用允許沒有例外。

由於用於HCAccessor隱式析構函數將是微不足道的並且因此noexcept(true),因爲它不調用任何功能,~HCAcessor,在沒有異常規範的,將被宣佈noexcept爲好。

相關問題