2012-10-04 66 views
6

可能重複:
How to clean initialized resources if exception thrown from constructor in c++如何正確處理構造函數中的異常?

如何處理在構造異常,如果我創建了6個對象和這些對象的創建5對象和失敗,在創建第6嗎?

謝謝。

+3

如何鏈接,Als給你在這裏http://stackoverflow.com/questions/12723492/how-to-clean-initialized-resources-if-exception-thrown-from-constructor-in-c?這個成員是否是對象? – ForEveR

+0

你需要什麼處理?通常情況下,您只需讓異常傳播,以便前5個對象被幹淨地銷燬。更多的上下文將有幫助 – jalf

+0

RAII。(http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) – ScaryAardvark

回答

1

當在構造函數中拋出異常時,所有完全構造的子對象都被銷燬。由於構造對象的析構函數關注它們的結果是一種很好的做法,因此這些子對象不需要做任何事情。當拋出異常時,正在執行的構造函數的主體中正在清除的內容仍然存在。但是,這與任何其他功能的清理沒有什麼不同。

請注意,銷燬順序與結構相反。也就是說,當所有的子物體尚未被破壞時,首先開始清理。然後成員被銷燬,然後是非虛擬基類,最後是虛擬基類。

3

通常的行爲只是讓異常傳播。對於任何完全構建的基類和成員,將調用析構函數 ; 如果前五個對象是成員,他們會正確地被 破壞。

可能發生問題的唯一情況是,如果您正在談論的對象是 已被動態分配(使用new)。如果這是 的情況:首先要問自己的是爲什麼?你爲什麼動態分配,而不是使對象成爲具體的成員?在我的經驗中,這樣的需求是非常非常罕見的,除了一些特殊的 的情況下(例如彙編防火牆習語),在這種情況下,通常會有 正好是類中的一個對象(例如指向 實現對象)。在這種情況下,沒有問題,因爲如果 該對象的new失敗,則沒有其他任何操作需要 撤銷。

如果你發現自己在極爲罕見的情況下,你真的 就必須使用動態分配有不止一個這樣的對象 (例如,因爲你有兩個子對象該是多態),那麼 你必須確保每個分配都包含在某種子對象中(一個智能指針可以做到這一點);一旦第一個 子對象被成功構建,如果構造函數在稍後的某個點失敗,它的析構函數將被調用 。

1

在處理異常的「核心」中,幾乎所有的東西都應該通過析構函數進行清理。例如,如果你「新」了一個對象,你會得到一個「原始」指針;如果某處出現異常,則必須確保此原始指針正確「刪除」d - 但請確保不要刪除尚未初始化的原始指針。另一方面,如果將該指針存儲到std :: unique_ptr中,則不必執行任何操作;但是,如果將該指針存儲在std :: unique_ptr中,則不必執行任何操作。當unique_ptr被銷燬時,對象被刪除,並且對象銷燬自動發生:當unique_ptr超出作用域時,編譯器調用清理,完全不可見(因此不會有更多的代碼混亂和大量的清理調用),並自動地沒有更多的「哎呀,當它需要那種罕見的道路,沒有人真正測試它忘記清理」)。

這同樣適用於幾乎所有的資源;有COM對象的「自動指針」(例如,在DirectX中使用),大多數框架應該爲您提供一個「範圍鎖定」類型對象來包裝互斥鎖(因此它在創建對象時鎖定互斥鎖,以及當它被破壞時解鎖它),並且你可以編寫微小的包裝來處理各種Windows句柄。基本上,如果你把所有的清理工作都放到了析構函數中,那麼你就不必爲了清理而「嘗試......拋出......重新拋出」。 「較大」對象的析構函數通常會非常簡單,因爲幾乎所有「包含」的對象都會被析構函數自動清理。