在C++中,這被認爲良好的編程習慣:C++嘗試捕捉做法
try {
// some code
}
catch(someException) {
// do something
}
catch (...)
{
// left empty <-- Good Practice???
}
在C++中,這被認爲良好的編程習慣:C++嘗試捕捉做法
try {
// some code
}
catch(someException) {
// do something
}
catch (...)
{
// left empty <-- Good Practice???
}
沒有!這是一個可怕的做法!
差不多隻有你應該catch (...)
而不重新拋出異常將在main()
捕捉任何其他未處理的異常,並在退出之前顯示或記錄錯誤。
如果你catch (...)
,你完全不知道拋出了什麼異常,因此你不知道是否繼續運行是安全的。
因此,您將在調試程序時遇到麻煩,因爲此全部封鎖將會隱藏您的錯誤。 – mcandre 2010-06-03 14:58:59
@mcandre:Visual Studio調試器提供第一次機會的異常處理,當拋出異常時該異常處理會中斷;我確信其他調試器也提供這種功能。 'main()'技巧中的'catch(...)'可以在不依賴於'std :: unexpected()'和'std :: terminate()'的情況下允許「正常」出口。 – 2010-06-03 15:03:22
而我從來沒有發現調試異常很容易,因爲堆棧被你破壞的時間毀了。因此,我通常會在發生異常的地方進行斷言。 – 2010-06-03 16:05:24
那麼這取決於你的應用程序和你正試圖解決的問題。但總的來說,吞下未知的例外並不是一個好主意。至少,我會記錄一些東西。
編輯:諾亞·羅伯茨指出,大約只有唯一的一次,這可能是一個合理的想法是在析構函數。禁止析構函數中的異常非常重要,否則可能有多個異常處於活動狀態。這可能發生,例如,如果拋出異常,並且由於堆棧展開,調用某個析構函數。如果該析構函數拋出異常,則會有2個異常處於活動狀態。然後C++將調用std :: terminate(),默認情況下會結束您的程序。你可以爲這個條件安裝一個處理程序,但是除了記錄發生的事情之外,你可以做的事情不多。
儘管如此,即使是在析構函數中,也應該記錄catch (...)
中的內容。但是,根據它是哪個析構函數,您可能沒有可用的日誌工具。但在大多數情況下,您仍然可以使用std::cerr
。
我不認爲在析構函數中使用catch(...)是不可接受的。如果您不確切知道某個操作可能拋出的異常以及在什麼情況下,您不應該在析構函數中執行該操作。 – 2010-06-03 18:58:33
你經常沒有選擇。如果你正在實現RAII,你必須撤銷你在構造函數中所做的事情。在第三方代碼中,在所有情況下拋出異常可能並不清楚。因此,通常只是「抓住(......)」來涵蓋所有情況。當然,如果可以的話,你應該記錄下來。 – 2010-06-03 20:26:22
這是那些「它取決於」的問題之一。如果你正在處理記錄不完善的第三方庫,它們繼續前進並定義了自己的異常,它們不會從std :: exception中繼承,你可能沒有其他選擇。然後,我只會將其留在我的代碼的調試部分。
不,這不是C++或任何其他語言的良好編程習慣。
沉默的失敗是不好的,遲早會咬你的。
如果你打算去catch (...)
最少你應該做的就是記錄你正在做的事情。如果您不使用RAII,您可能還需要delete
某些對象。
很好的做法就是:
try {
// some code
}
catch(const someException & e) {
// do something
}
因爲你知道的例外(S)你想趕上什麼。 (...)應該只在你的main()和線程的入口點(沒有異常應該離開線程),當然是catch(const std :: exception & e)。
+1用於添加'const&'。 – Johnsyweb 2010-06-03 15:06:05
我只能想到這可能是必要的 - 雖然這仍然不意味着它是好的 - 是在一個析構函數。析構函數不能拋出,或者你會遇到比任何異常都要糟糕的問題(可能是bad_alloc)。如果沒有什麼可以做的,當某些事情拋出時,你的捕獲將是空的。你不能重新拋出,因爲你在一個析構函數中...這是你在這種情況下所能做的。
儘管如此,在那裏或某些東西的斷言將是有保證的。
當然,其他人提到過線程。我只是不做MT,所以我不知道那裏的問題。
飲食異常是一個壞主意。
至少,爲您的例外實施某種日誌記錄。您可能需要考慮重新拋出異常,並在錯誤消息中更好地描述問題。
作爲一個標準的做法,這是一個非常糟糕的主意。如果當你不知道如何處理它們時開始吞噬異常,那麼你就是一個。阻止它們在調用堆棧中更適合的地方處理,以及b。給你的程序機會繼續在一些錯誤的狀態。
但是,那就是說,作爲程序員的你已經做出了正確和合乎邏輯的判斷,認爲這是一個適當的時候吞下異常的可能性。這可能需要執行後續步驟,例如執行清理並通知用戶他們啓動的操作失敗。
底線,如果你不能確定捕捉的後果 - 不要捕捉。
其實它確實取決於你的整個程序打算做什麼,然而大多數情況下,吞併異常並繼續執行就像沒有任何事情發生一樣,你不需要被告知代碼實際上存在什麼問題,它在哪裏崩潰等...
BaşakBilgi
絕不說絕對。 我會說你應該幾乎永遠不會吞下異常。然而,這裏是我的代碼中一個地方,我都做到了沒有真正困擾我:
class _ACLASS dstream
: public ofstream
{
//...
long GetSize (void);
//...
Protected:
string CheckRotation(void);
//...
};
string dstream::CheckRotation(void)
{
//...
// rotate if they aren't the same (it's a new day)
// or our current file size exceeds the limit.
if (currDay != newDay || GetSize() > fileSizeLimit * ONE_MEGABYTE)
{
//...
Purge(); // while all files are closed, look for purge opportunity
clear();
open(Destination);
//...
}
// Return current file size
long dstream::GetSize (void)
{
long retval =0;
try { // PBI 1227 was caused by this not being trapped.
retval = (long)tellp();
} catch (...) {
retval =0;
} // Swallow the exception if any
return retval;
}
在這裏,我只是想確定我的日誌文件已經超過1M的字節(或hwever許多M個字節允許由fileSizeLimit),如果是這樣,旋轉日誌。如果我在這裏遇到異常,我只會向調用者報告一個0字節的大小,並且調用者此時不會選擇旋轉日誌。在下一次通話中,它可能會得到一個正確的答案並通過。
我想如果tellp()每次調用都會拋出異常,我的日誌將不會旋轉,直到午夜。但我懷疑這是否會發生(我從來沒有在現場看到過)
你是**而不是**只是'吞嚥'那個例外;當發生異常時,你正在做某事*將'retval'設置爲'0'。 – 2012-11-06 17:24:56
我從來沒有使用......除了'main'作爲最後的手段。如果我想要捕獲它們,我使用'std :: exception',至少你可以打印它並且瞭解原因 – 2010-06-03 16:41:35
並且通過引用來捕獲它。 – ereOn 2011-05-20 13:38:14