2015-01-13 39 views
48

我不確定這是編譯器的問題還是如果我做錯了什麼。我正在使用Visual Studio 2013編譯器。作爲函數的構造函數嘗試塊 - 異常中止程序

我有一個類,我需要獲取我的構造函數初始值設定項列表中的大量資源,其中大部分資源可能會引發異常。我在函數try塊中包含了成員初始值設定項列表,並在那裏發現了異常。但即使catch子句不會重新拋出異常,我的程序仍會中止。我不允許發佈實際的代碼。所以我用這個等效的演示代碼重現了這個問題。有人可以幫我解決這個問題嗎?

#include <iostream> 
using namespace std; 
class A{ 
public: 
    A() try : i{ 0 }{ throw 5; } 
    catch (...){ cout << "Exception" << endl; } 
private: 
    int i; 
}; 


int main(){ 
    A obj; 
} 

在執行此代碼時,我得到一個windows警報「abort()has called」。所以我想系統將這個視爲一個未捕獲的異常並調用terminate()。

另一方面,如果我在main()中將對象的構造包裝在try-catch塊中,那麼異常被正確捕獲並且程序正常結束。

有人可以告訴我,如果我在這裏做錯了什麼嗎?

+4

看看http://www.gotw.ca/gotw/066.htm有關此問題的 –

+0

的討論非常感謝Jan Herrmann。對於標準來說,如果不重新拋出異常,或者如果不從構造函數的try塊中拋出新的概念,那麼它將在catch塊的末尾自動重新生成。這現在非常有意義。也許正如建議pimpl成語是我應該開始使用。再次感謝 – Madhusudhan

+20

*「我不允許發佈實際的代碼。所以我用這個等效的演示代碼重現了這個問題。「*您已經做出了非常好的[MCVE](https://stackoverflow.com/help/mcve)。 – 5gon12eder

回答

30

有一個相關的gotw

http://gotw.ca/gotw/066.htm

基本上即使你沒有在你的catch塊拋出的異常會自動重新拋出

如果處理器主體包含的聲明「扔;」那麼捕獲 塊顯然會重新拋出A :: A()或B :: B()發出的任何異常。不太明顯的,但在標準中明確指出的是 ,如果catch塊沒有拋出(重新拋出原始的 異常,或拋出一些新東西),並且控制到達構造函數或析構函數的catch塊的末尾,那麼原始的 異常會自動重新排列。

+0

該頁面非常優秀。在這個問題之前,不知道函數嘗試塊的語法;從這個環節學到了很多東西!特別是,有一個奇妙的比喻:「如果任何基地或成員物體的構建失敗,那麼如果任何人的重要器官從未形成,則整個物體必須失敗......沒有辦法讓人類[出生]。 – OJFord

+0

整個gotw網站是任何C++開發者的金礦!隨着Bjarne的網站,parashift,cppreference和cplusplus –

+0

自從我上面的評論以來,我一直在48分鐘內發現這一點!最近的一次恥辱是1/1/08。 – OJFord

22

這是根據the cppreference.com documentation for function-try blocks正常行爲:所謂功能試塊在構造函數和析構函數必須從它的catch子句拋出,否則有趕超條款後隱式重新拋出。

這非常有意義:對象A尚未正確構建,因此不處於適合使用的狀態:它必須拋出異常。您必須確保構建對象的地方是否成功,例如main()中的示例。

+4

Upvoting因爲這個答案比引用標準更具人類可讀的答案。對於OP:您的問題是您的一個或多個成員處於未構建狀態(因爲您不知道哪個成員的構建投擲,您不知道哪些成員已完全構建)。因此你的班級沒有完全建造。重新拋出確保你不能使用這個實例。完全構建的成員將被適當地破壞。 –

9

異常無法在構造函數function-try-block中捕獲。

n3376 15.2/15

當前處理的異常,如果控制到達一個構造或析構函數的功能試塊的處理程序結束 被重新拋出。

你應該在對象創建的地方抓住它。