簡體   English   中英

並非所有控制路徑都返回值? 警告

[英]Not All Control Paths Return a Value? Warning

我有一小段代碼在編譯時給出了以下警告:

'BGOLUB :: Containers :: Stack :: Pop':並非所有控制路徑都返回一個值

這是代碼:

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;
}
}

有什么建議?

非常感謝!

有什么建議?

編譯器給你最好的建議。 並非函數中的所有控制路徑都包含return語句,並且您的函數應該返回一個值。

如果拋出異常並將控制轉移到catch處理程序,那么該處理程序將向cerr打印一些內容,然后從函數末尾流出而不實際return任何內容。

這是未定義的行為 根據C ++ 11標准的第6.6.3 / 2段:

[..]從函數末尾流出相當於沒有值的返回; 這會導致值返回函數中的未定義行為

對於default-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包裝器編寫異常安全的代碼。 Jon Kalb這個由兩部分組成的演講中給出了這方面的優秀指導。

特別是,避免編寫catch (...)處理程序:發明異常是為了防止程序員忽略錯誤,並且在沒有重新拋出它們的情況下將它們全部吞沒在通用處理程序中是忽略它們的最佳方法。


注意:

請注意, Pop()的實現有點問題:如果在修改堆棧指針之后將元素返回給調用者時T的復制構造函數或移動構造函數拋出會發生什么?

這就是為什么C ++標准庫定義了兩個獨立的函數pop()top()原因:因為它允許提供強有力的保證 ,即為pop()操作提供事務語義 - 要么刪除元素而不拋出異常,或該功能根本沒有效果。

你需要重新拋出異常,或者在函數末尾返回一些可能是T()的東西。

拋出異常時,它將被兩個catch語句中的一個捕獲。 但是,它們仍然需要從函數return一個值。 您可以在函數末尾放置一個return語句。

但是,如果Pop因為Stack為空而拋出異常,那么讓異常傳播出函數會更有意義。 為什么Pop本身會試圖處理異常情況?

我建議在所有if語句中使用括號,即使是單行主體也是如此。 它們不是絕對必要的,你可以在沒有它們的情況下編寫完全合法的代碼,但是它們使你的代碼更具可讀性,並且這樣的錯誤將更容易找到。

此外,您似乎對異常的工作方式存在根本性的誤解。 如果您的代碼遇到異常,它將直接跳轉到catch塊,而不執行try塊中的任何后續代碼。 因此,永遠不會到達try塊中的return語句,並且你的函數不會返回任何內容,因為catch塊缺少return語句。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM