2011-05-09 76 views
4
enum ENUM(Option1,Option2,Option3); 

string func(ENUM x) 
{ 
switch(x) 
{ 
    case Option1: return "Option1"; 
    case Option2: return "Option2"; 
    case Option3: return "Option3"; 
} 
} 

這編譯和工作,但給編譯器警告,並非所有控制路徑返回。然而,如果你恰當地使用枚舉,那不是這種情況嗎?如果添加了另一個ENUM val,我希望編譯失敗,但只要覆蓋了所有的情況,我希望它能夠無警告地編譯。打開枚舉時的編譯器警告

這是編譯器保護不受嚴重流失的值,它只是C++的一部分,需要與生活在一起?

+0

嘗試添加'default'路徑。 – Archie 2011-05-09 10:39:26

+2

@Archie:錯誤的解決方案,如果你忘記了一個枚舉成員,那麼你沒有警告。 – 2011-05-09 12:27:47

+2

@Matthieu:這不完全是最佳做法。我會一直添加默認值。如果您想要警告您忘記了某個值,請在默認情況下添加斷言或拋出異常。編譯器不是爲了提醒你必須做的事情,而是編譯你的代碼。 – 2011-05-09 13:08:27

回答

3

如果由於某種原因,會發生什麼x既不是Option1也不是Option2Option3

當然,你可以認爲不會發生,但由於該方法返回的東西,你有兩個選擇:

  • 末增加return string("");

  • switch添加default返回string("")

正如CodeGray指出的那樣,第二種選擇可以說是更好的風格。您也可以返回除空字符串之外的其他內容。

+0

+1,你需要一個默認的返回值,但我肯定會在最後添加一個'default'的情況。我認爲這更具可讀性。 – 2011-05-09 10:40:50

+0

你用'return null'表示什麼意思?如果你的意思是'NULL',那麼你有其他問題,因爲'std :: string'不喜歡'NULL'。 – rve 2011-05-09 10:43:10

+0

在C++中,'string'是一個值對象,所以你不能返回一個空指針(順便說一下,它在C++中被命名爲「NULL」)。在這種情況下,您可以使用「」,但是,請參閱我對解決方案的回答,您根本不必發明虛假返回值。 – Lindydancer 2011-05-09 10:44:28

5

從編譯器的角度來看,枚舉的類型是一個整數,所以x的值仍然可能是其他情況之一。

通常情況下,我會添加一個觸發內部錯誤的default:標籤。

提示:如果您將調用的實習生錯誤包裝在無限循環中,則不必發明僞造的返回值。例如:

#define IntErr(x) for(;;) { InternalError(x); } 
string func(ENUM x) 
{ 
    switch(x) 
    { 
    case Option1: return "Option1"; 
    case Option2: return "Option2"; 
    case Option3: return "Option3"; 
    default: IntErr("Unexpected ENUM value"); 
} 
} 
+0

我沒有意識到編譯器直接將enums直接插入整數,這確實解釋了它......但爲什麼它首先做到這一點?布爾人是同樣對待還是保持自己的類型? – 2011-05-09 14:01:27

+0

無限循環如何提供幫助?假冒僞劣價值比永不完成執行還好嗎? – Grault 2015-04-11 15:46:58

+0

@Jesdisciple,它不是一個永不完成的執行,函數'InternalError'停止執行。 'for(;;)'確保你不必寫一個「死」的return語句。 – Lindydancer 2015-04-11 19:37:17

3

在C++中,枚舉是不安全的。你不能指望一個枚舉值在枚舉聲明中定義的值之一:

  • 它可以被未初始化(因此垃圾)
  • 你可以從int

有不當static_cast因此,即使覆蓋枚舉的所有元素,編譯器也不能指望返回。但從功能上講,這確實是一種錯誤狀態。

有兩種方式作出反應:

  • 一個default情況下添加到您的enum
  • 添加一條語句開關

爲了明智的選擇後,請記住,編譯器可能(如果你問的話)在switch沒有涵蓋enum的所有情況下觸發警告,條件是沒有default聲明。智能編譯器(即Clang)允許將警告分別映射到錯誤,這極大地幫助捕獲這些錯誤。

因此,你必須決定採取:

  • 如果你想通知當你忘記更新枚舉後,要改變這種方法,那麼如果你想成爲不使用default
  • 能夠更新枚舉,並忽略此開關,然後用default

最後,你必須決定如何作出反應,並指出,使用一個運行時錯誤是使用默認聲明不一致的(最好在捕捉錯誤COM樁時儘可能):

  • 忽略錯誤並返回一些預定義的值
  • 拋出一個異常(與枚舉值,請)
  • 斷言(因此崩潰很難在調試,獲得內存轉儲,和做其他事情在發行,像什麼,或拋出異常)

我個人的最愛是UNREACHABLE(Text_)宏,它引發的調試內存轉儲(讓我得到一個完整的曲線)和日誌一個錯誤並拋出釋放(以便服務器停止處理這個請求st,但不會完全停止響應)。

這讓這樣的代碼,例如:

char const* func(ENUM x) 
{ 
switch(x) 
{ 
    case Option1: return "Option1"; 
    case Option2: return "Option2"; 
    case Option3: return "Option3"; 
} 
UNREACHABLE("func(ENUM)") 
} 
+2

第一種情況似乎是似是而非,因爲如果該值未初始化,則具有UB,並且默認情況下不會對您有所幫助。 – Antimony 2014-05-06 02:15:56

+0

@Antimony:它實際上更加惡毒,在調試模式下,gcc會給你一個'0'(通常是enum的第一個成員),而在發佈模式下,由於優化,任何事情都可能發生......這往往足夠結果在一個垃圾值(和運氣,警告!)。顯然,我不會建議依靠它,因爲根據定義UB是不可靠的。 – 2014-05-06 06:38:35