2012-04-28 21 views
8

比方說,我有一個枚舉。要在交換機的默認標籤中放入什麼?

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE}; 

,後來我有這樣的功能:

void Function (ShapeName const shape){ 

    switch (shape){ 
     case ShapeName::TRIANGLE: 
      DoSomething1(); 
      break; 

     case ShapeName::CIRCLE: 
      DoSomething2(); 
      break; 

     case ShapeName::SQUARE: 
      DoSomething3(); 
      break; 

     default: 
      //THIS CODE BLOCK SHOULD NEVER BE EXECUTED! 
    } 

    return; 
} 

雖然默認標籤應永遠不會被執行,我想考慮到可能出現的潛在的bug,如果一個程序員又增加了價值'ShapeName',它不在交換機中考慮。
你會推薦我做什麼?

1.斷言
我可以用一個斷言,但我是什麼主張?

assert(false); //? 

2.例外
我可以拋出一個異常,但我不認爲這是非常好的做法。我認爲異常是因爲某些環境而無法預測的運行時事件。

3.退出
我可以立即退出程序並出現錯誤。 這感覺是最好的想法,但我不確定這是否是好的做法。我認爲斷言的優勢在於,當你準備發佈程序時,你可以將它們全部關閉。然後,所有的斷言代碼將不再存在。


也許有另一種方式,我不知道。我確實使用了一個編譯器標誌,它會警告未考慮的值,但我仍然想知道其他人推薦的內容。

+0

4.你能告訴你的編譯器警告它嗎?這是我期望的舊式枚舉的一個選項。 – 2012-04-28 02:20:53

+0

@SteveJessop g ++ -w -Wall -Wextra -Wswitch -Wwitch-default -Wswitch -enum -std = C++ 0x -o main main.cpp 奇怪的是,我沒有得到上述代碼的警告。我添加了另一個ShapeName並擺脫了默認標籤。依然沒有! – 2012-04-28 02:30:16

+0

大鼠。儘管如此,C++ 11的實現還沒有完成,所以我們可以活在希望之中。 – 2012-04-28 02:37:39

回答

9

我喜歡用信息性的信息斷言的想法。試試這個:

assert (!"The default case of so-so switch was reached."); 

這總是返回false,但是提供了一條可以使用的消息。

編輯:
我發現了源代碼,我將這個概念從我的記憶中拉出來;它在下面的書中:
C++編碼標準 - 101規則和指導

+2

或者如果你不喜歡拼寫的方式,'assert(false &&「message);' – 2012-04-28 02:25:57

+3

並且記住斷言通常會從」release「版本中刪除。 – 2012-04-28 02:30:05

+1

對於發佈版本,您還可以使用編譯器的等效函數['__assume(0)'](http://msdn.microsoft.com/en-us/library/1b3fsfxw.aspx)作爲優化提示。 – ildjarn 2012-04-28 02:36:42

0

我想對我來說它將取決於什麼DoSomething#方法。

如果它稍後會導致不太正常的崩潰,那麼肯定要中斷運行時,這會被調用時解釋爲「使用無效枚舉:enumName調用的函數」,或者給開發人員通知他們沒有更新這個轉換語句,而不是讓他們想知道以後是否會失敗。

4

對於這種特定情況,您打開枚舉標記並處理所有情況時,我的首選是忽略默認值。這樣,使用任何合理的編譯器,如果有人向枚舉添加了新標籤而不是交換機,則會收到編譯時警告,提示該標籤未在交換機中處理。

+0

顯然GCC在新的C++ 11枚舉類方面是不合理的,儘管提問者沒有說GCC的版本。 – 2012-04-28 02:40:57

+0

@SteveJessop gcc(Ubuntu/Linaro 4.6.1-9ubuntu3)4.6.1 – 2012-04-29 02:48:54

+0

@SteveJessop:gcc(試過4.4.5,4.5.2和4.6.3)給我「'警告:枚舉值'OTHER'不是如果我刪除默認並添加一個'OTHER'標籤... – 2012-07-25 18:02:10

0

簡短回答:使用多態消除問題。

龍答: 解決根本問題的最簡單的方法(?即如何防止遺漏項switch語句)將避免使用switch語句如果有被遺忘條目的機會。 Switch語句在本地環境中非常有用,但是如果它們所代表的邏輯在多個位置被複制,那麼就有可能忘記更新它,並且設置自己的運行時錯誤。

class Shape 
{ 
    // functionality MUST be added for new shape types 
    // or a compile error will occur 
    virtual void DoSomething() const = 0; 
}; 

void Function (Shape const & shape){ 
    return shape.DoSomething(); 
} 

switch語句可能仍然在創建網站有用:

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE}; 

unique_ptr<Shape> MakeShape (ShapeName const shape){ 
    switch (shape){ 
     case ShapeName::TRIANGLE: 
      return unique_ptr<Shape>(new Triangle()); 

     case ShapeName::CIRCLE: 
      return unique_ptr<Shape>(new Circle()); 

     case ShapeName::SQUARE: 
      return unique_ptr<Shape>(new Square()); 
    } 

    throw std::runtime_error(); 
    // or whichever option you prefer from the other answers 
} 

但是,這僅地方的邏輯存在。甚至可以在與靜態多態性改進:

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE,ELLIPSE}; 

template< ShapeName shape > 
unique_ptr<Shape> MakeShape(); 

template<> 
unique_ptr<Shape> MakeShape<ShapeName::TRIANGLE>() 
{ 
    return unique_ptr<Shape>(new Triangle()); 
} 

template<> 
unique_ptr<Shape> MakeShape<ShapeName::CIRCLE>() 
{ 
    return unique_ptr<Shape>(new Circle()); 
} 

template<> 
unique_ptr<Shape> MakeShape<ShapeName::SQUARE>() 
{ 
    return unique_ptr<Shape>(new Square()); 
} 

int main() 
{ 
    MakeShape<ShapeName::TRIANGLE>(); // okay 

    MakeShape<ShapeName::ELLIPSE>(); // compile error 
} 

更多信息,請參見Martin Folwer

+0

爲什麼選擇倒票?我認爲這個人爲的例子是最好的解決方案。正因如此,Switch語句可能是一種代碼異味。 'default'的問題是你沒有得到一個編譯器的警告,如果您處於每種情況都會返回的開關類型(例如,工廠)中,那麼沒有'default',編譯器會抱怨函數結束時返回的不足。我認爲MSVC曾經有一個無法到達的宏在這裏提供幫助。 – 2014-12-02 23:42:35