2013-04-23 83 views
3

Ive得到的代碼是給我在編譯如下警告短位:並非所有控制路徑都返回一個值?警告:

「BGOLUB ::容器::堆棧::流行」:不是所有的控制路徑返回一個值

下面是代碼:

template<typename T> 
T Stack<T>::Pop()                   
{ 

try 
{ 
    if (m_index<0) throw OutOfBoundsException(m_index); 

    --m_index; 
    return(m_array[m_index]); 
} 

catch(OutOfBoundsException&) 
{ 
    cerr<<"Underflow Index = "<<m_index<<endl; 
} 

catch(...) 
{ 
    cerr<<"Unhandled Error Occured"<<endl; 
} 
} 

有什麼建議?

非常感謝!

+0

您需要在您的catch塊中返回一些值 – 2013-04-23 18:05:51

回答

18

有什麼建議嗎?

編譯器給你最好的建議。並非函數中的所有控制路徑都包含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()操作 - 無論是元素沒有被拋出的異常刪除,或者該功能根本沒有效果。

+0

要展開最後一點:捕獲異常,以便處理它。記錄錯誤不處理它。 – 2013-04-23 18:12:22

+0

@sftrabbit:是的,一般處理或翻譯。但是你是對的,日誌不能處理。我應該澄清這一點,謝謝 – 2013-04-23 18:13:28

+3

優秀的答案。 – 2013-04-23 18:16:16

1

您需要重新拋出異常,或者在函數結束時返回可能的T()。

1

當引發異常時,它將被兩個catch語句之一捕獲。但是,他們仍然需要return這個函數的一個值。你可以在你的函數的最後放置一個return聲明。

但是,如果Pop由於Stack爲空而引發異常,讓異常傳播出函數更有意義。爲什麼Pop本身試圖處理特殊情況?

0

我會建議在所有的if聲明中使用括號,即使是單行的機構也是如此。它們不是絕對必要的,你可以在沒有它們的情況下編寫完全合法的代碼,但它們使你的代碼更加可讀,像這樣的錯誤將更容易找到。

此外,看起來你對於例外如何工作有一個基本的誤解。如果您的代碼遇到異常,它將直接跳轉到catch塊,並且不會執行try塊中的任何後續代碼。因此,try塊中的return語句塊將永遠不會到達,並且您的函數不會返回任何內容,因爲catch塊沒有return語句。

您可以通過在catch塊中添加return語句來解決此問題。

相關問題