2012-04-28 18 views
8

Giả sử tôi có một điều tra.Điều gì được đặt trong nhãn mặc định của nút chuyển?

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

và sau đó tôi có một chức năng như thế này:

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

Mặc dù nhãn mặc định không bao giờ được thực hiện, tôi muốn giải thích cho các lỗi tiềm tàng có thể xảy ra nếu một lập trình viên cho biết thêm một giá trị để 'ShapeName' và nó không được tính trong chuyển đổi.
Bạn nên làm gì?

1. Khẳng định
tôi có thể sử dụng một sự khẳng định, nhưng những gì tôi khẳng định?

assert(false); //? 

2. Trường hợp ngoại lệ
tôi có thể ném một ngoại lệ, nhưng tôi không nghĩ rằng sẽ được thực hành rất tốt. Tôi có ấn tượng rằng các trường hợp ngoại lệ dành cho các sự kiện thời gian chạy không thể dự đoán được do một số môi trường nhất định.

3. Thoát
Tôi chỉ có thể thoát khỏi chương trình ngay lập tức với một lỗi. Điều đó giống như ý tưởng hay nhất, nhưng tôi không chắc liệu đó có phải là thực hành tốt hay không. Tôi nghĩ rằng lợi thế của các xác nhận là bạn có thể tắt tất cả khi bạn đã sẵn sàng tàu chương trình. Sau đó, tất cả mã xác nhận đó sẽ không còn tồn tại nữa.


Có thể có một cách khác mà tôi không biết. Tôi sử dụng một lá cờ trình biên dịch cảnh báo về không có giá trị cho các giá trị, nhưng tôi vẫn muốn biết những gì người khác đề nghị.

+0

4. Bạn có thể yêu cầu trình biên dịch cảnh báo không? Đó là một lựa chọn mà tôi mong đợi cho các enums kiểu cũ. –

+0

@SteveJessop g ++ -w -Wall -Wextra -Wswitch -Wswitch-default -Wswitch-enum -std = C++ 0x-main main.cpp lạ, tôi không nhận được cảnh báo nào cả với mã ở trên. Tôi đã thêm một ShapeName khác và đã loại bỏ nhãn mặc định. Vẫn không có gì! –

+0

Chuột. Mặc dù vậy, việc thực hiện C++ 11 chưa hoàn tất, vì vậy chúng ta có thể sống với hy vọng. –

Trả lời

9

Tôi thích ý tưởng khẳng định bằng một thông báo mang tính thông tin. Hãy thử điều này:

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

Điều này luôn trả về false, nhưng cung cấp thông báo bạn có thể sử dụng.

Chỉnh sửa:
Tôi tìm thấy nguồn tôi đã lấy khái niệm này ra khỏi bộ nhớ của mình; trong sách sau:
Tiêu chuẩn mã hóa C++ - 101 Quy tắc và nguyên tắc

+2

Hoặc nếu bạn không thích cách đánh vần, 'assert (false &&" message ");' –

+3

Và hãy nhớ rằng các xác nhận thường bị loại bỏ khỏi các bản dựng "release". –

+1

Đối với bản phát hành bản phát hành, bạn cũng có thể sử dụng trình biên dịch tương đương với ['__assume (0)'] (http://msdn.microsoft.com/en-us/library/1b3fsfxw.aspx) làm gợi ý tối ưu hóa. – ildjarn

0

Tôi đoán với tôi nó sẽ phụ thuộc phần nào vào phương pháp DoSomething # làm.

Nếu nó sẽ gây ra một vụ tai nạn kém duyên dáng sau này bạn chắc chắn muốn ngắt thời gian chạy khi nó được gọi với lời giải thích "hàm được gọi là enum không hợp lệ: enumName" hoặc cái gì đó để thông báo cho nhà phát triển tuyên bố chuyển đổi này, thay vì để họ tự hỏi nếu có điều gì đó không thành công sau này.

4

Tùy chọn của tôi cho trường hợp cụ thể này, nơi bạn đang chuyển sang thẻ enum và xử lý tất cả các trường hợp, là bỏ mặc định. Bằng cách đó, với bất kỳ trình biên dịch hợp lý nào, nếu ai đó thêm thẻ mới vào enum và không chuyển đổi, bạn sẽ nhận được cảnh báo thời gian biên dịch về thẻ không được xử lý trong chuyển đổi.

+0

Rõ ràng GCC là không hợp lý đối với các lớp enum C++ 11 mới, mặc dù người hỏi không nói phiên bản GCC. –

+0

@SteveJessop gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 –

+0

@SteveJessop: gcc (đã thử 4.4.5, 4.5.2 và 4.6.3) cho tôi "' cảnh báo: giá trị đếm 'OTHER' không được xử lý trong chuyển đổi' "nếu tôi xóa mặc định và thêm thẻ' OTHER' ... –

0

Câu trả lời ngắn: Sử dụng đa hình để loại bỏ sự cố.

dài câu trả lời: Cách dễ nhất để giải quyết vấn đề gốc (? Ví dụ: Làm thế nào để ngăn chặn tuyên bố chuyển đổi với mục mất tích) sẽ là để tránh sử dụng công tắc báo cáo nếu có một cơ hội các mục bị lãng quên. Các câu lệnh switch rất hữu ích trong các ngữ cảnh cục bộ, nhưng nếu logic mà chúng đại diện được nhân đôi ở nhiều vị trí thì có khả năng quên cập nhật một và bạn đang thiết lập cho mình các lỗi thời gian chạy.

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

Lệnh switch vẫn có thể hữu ích ở chỗ tạo:

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 
} 

Nhưng đó là nơi chỉ logic tồn tại. Và thậm chí điều đó có thể được cải thiện khi có đa hình tĩnh:

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 
} 

Xem Martin Folwer để biết thêm thông tin.

+0

Tại sao lại bỏ phiếu xuống? Tôi nghĩ cho ví dụ này, nó là giải pháp tốt nhất. Các câu lệnh chuyển đổi có thể là một mùi mã, vì chính xác lý do này. Vấn đề với 'default' là bạn không nhận được một cảnh báo trình biên dịch cho một trường hợp bị bỏ qua; không có 'mặc định' nếu bạn đang ở trong loại chuyển đổi mà mỗi trường hợp trả về (ví dụ: nhà máy), trình biên dịch sẽ phàn nàn về việc thiếu trả lại ở cuối hàm. Tôi nghĩ rằng MSVC đã từng có một macro không thể truy cập để trợ giúp ở đây. –