有什麼建議嗎?
編譯器給你最好的建議。並非函數中的所有控制路徑都包含return
語句,並且函數應該返回一個值。
如果拋出異常並且控制權被轉移到catch
處理程序,那麼該處理程序將打印一些內容到cerr
,然後在函數的末尾流出,而實際上並不需要任何東西。
這是未定義的行爲。根據C++ 11標準的第6.6.3/2段:
[..]流出函數結尾等於沒有值的返回; 這會導致在返回值函數中出現未定義的 行爲。
對於默認constructible值,可以通過正確的函數結束前添加一個return T()
聲明解決這個問題:然而
template<typename T>
T Stack<T>::Pop()
{
try
{
// ...
}
catch (OutOfBoundsException&)
{
// ...
}
catch (...)
{
// ...
}
return T();
// ^^^^^^^^^^^
}
較爲合理的做法是,以不有Pop()
吞下例外,而是重新拋出它。 Pop()
沒有就如何從錯誤中恢復的戰略級的信息發生在這種情況下:
template<typename T>
T Stack<T>::Pop()
{
try
{
// ...
}
catch (OutOfBoundsException&)
{
// ...
throw; // <== Re-throw after printing the diagnostic
}
catch (...)
{
// ...
throw; // <== Re-throw after printing the diagnostic
}
}
更妙的是,如果用於記錄一個錯誤信息的責任不屬於Pop()
可言,因爲Pop()
是在某種意義上可能會被不同需求的代碼重複使用(有些可能不想記錄任何內容,有些可能希望將消息記錄到文件中,有些可能希望以不同的語言記錄消息,等等)。
所以你的功能更合理的版本實際上是:
template<typename T>
T Stack<T>::Pop()
{
if (m_index<0) throw OutOfBoundsException(m_index);
--m_index;
return(m_array[m_index]);
}
在一般情況下,你應該嘗試(沒有雙關語意),以避免try/catch
塊,除非你有:
- 翻譯一個例外
- 從錯誤中恢復(但你需要這樣做的戰略知識)
如果這不是你的任務(如上面的函數Pop()
),在大多數情況下,最好的辦法是不會處理所有的異常並讓它們向上傳播調用堆棧。
引述Dave Abrahams:
經常處理異常的最好的辦法是無法處理它們。如果你可以讓他們通過你的代碼,並允許析構函數來處理清理,你的代碼將變得更清晰。
爲了避免內存泄露,資源,或一般職責,編寫代碼,使用適當的RAII包裝異常安全。這種意義上的優秀指導原則在this two-part talk by Jon Kalb中給出。
特別是,避免編寫catch (...)
處理程序:發明異常是爲了防止程序員忽略錯誤,並在通用處理程序中吞併它們而不重新拋出它們是忽略它們的最佳方式。
注:
注意,您的Pop()
實施是一個有點問題:如果拷貝構造函數或移動的T
構造會發生什麼返回元素時返回給調用者拋出,之後你已經修改了堆棧指針?
這就是爲什麼C++標準庫定義了兩個獨立的功能pop()
和top()
:因爲它允許提供有力保障,即給事務語義你pop()
操作 - 無論是元素沒有被拋出的異常刪除,或者該功能根本沒有效果。
您需要在您的catch塊中返回一些值 – 2013-04-23 18:05:51