2010-11-05 22 views
1

喂例外解開,C++:堆棧是不是拋出

我有一個很奇怪的問題,在我的C++項目之一: 我寫了一個C++的Socket封裝,嘗試連接到指定主機和端口(通過IPv4/TCP),並拋出一個SocketException(從std :: runtime_error派生),如果發生錯誤(例如'連接被拒絕')。異常被正確捕獲並且錯誤消息按預期寫入控制檯,但顯然我的Socket類的析構函數未被調用(它也應該向std :: cerr輸出消息,但消息僅在連接正常工作時纔會顯示並且如果套接字超出堆棧,套接字將在以後被銷燬,例如,在嘗試使用套接字的函數結束時)。析構函數應關閉封裝的套接字,但在拋出異常時,套接字保持打開狀態(您可以使用lsof作爲未知類型的套接字來查看它),因此絕不會執行析構函數中的任何代碼)。 由於我不能用簡單的測試用例來重現這個問題,我的猜測是它在某種程度上與我的項目的相當複雜的結構有關:我有一個核心應用程序,它包含Socket類的代碼並提供一個Singleton類提供了實現用於通信的協議並返回請求結果的方法,每次調用其中一個方法都會生成它自己的Socket實例,併爲其提供有關要使用的主機和端口的必要信息。爲了簡化套接字的生成和管理,我們使用了一個std :: auto_ptr,它應該刪除Socket if方法已經完成並且清理了堆棧,根據控制檯的輸出它可以正常工作,但是對拋出的異常應該以相同的方式工作,至少這是我的意見到現在爲止。 核心能夠通過dlopen以共享對象格式加載插件,並通過共享對象中的extern C聲明函數獲取指向插件類實例的指針。 此實例現在使用核心提供的Singleton與服務器進行通信並顯示檢索到的數據。

我的問題是:使用共享對象時是否存在堆棧展開的限制,或者我應該在哪裏尋找錯過的元素以使其正常工作?

+4

代碼勝於雄辯職位的代碼,它會更容易分析 – 2010-11-05 12:14:37

+0

其他信息:OS,這是在試圖爲Linux的,GCC 4.3.2(Debian Lenny)和GCC 4.4.x(Sabayon和Ubuntu Linux),glibc版本範圍從2.7到2.11 – crispinus 2010-11-05 12:14:40

+0

你準備發生的事情沒有發生,程序很複雜,怎麼了? – 2010-11-05 12:15:06

回答

7

如果您的異常從構造函數中拋出,析構函數將不會被調用。

+0

在這種情況下,[C++ FAQ](http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10)可能會有所幫助。 – 2010-11-05 12:20:55

+2

請注意,已完全構建的成員和基類將調用它們的析構函數。因此,最好的解決方案是將問題分爲兩部分:一部分管理資源,另一部分使用資源完成所需工作。 Google在RAII上獲取更多信息。 – Sjoerd 2010-11-05 12:58:25

+0

@Alf P. Steinbach:我對VC++ 10.0中這個剩餘的錯誤非常感興趣,你會如此善良以啓迪我:)? – 2010-11-05 13:23:04

0

好吧,忘了那個。代碼中的另一個外觀表明可能已經在構造函數中拋出了一個異常,所以析構函數不會被調用,因爲它在C++標準中有所描述。不拋出構造函數解決了這個問題。這就是Java中的編程對你的C++技能所做的事^^ 請原諒。

+3

好的,所以Armen Tsirunyan是對的。你應該upvote /接受他的答案。 – 2010-11-05 12:24:55

+0

當你編寫C++時,你還應該得到一本C++書,並忘記Java。也聽起來你的班級做得太多了。要麼管理*一個*資源,要麼*使用*多個資源。如果獲得資源失敗,則應該拋出。如果這些東西混亂了,你做錯了。 – GManNickG 2010-11-05 15:54:25

0

如果您在Linux上進行編程,您可能會觸發從共享庫拋出的異常沒有正確捕獲的問題(異常類型確定問題)。這個問題解釋herehere,我相信你可以谷歌更多的網頁解釋相同的問題。 。

如果這是一個問題,我仍然在尋找一個解決方案:(