2012-07-18 34 views
10

Có an toàn để giả định rằng static_cast sẽ không bao giờ ném một ngoại lệ?static_cast có thể ném một ngoại lệ trong C++?

Đối với một int để Enum cast, một ngoại lệ không được ném ngay cả khi nó không hợp lệ. Tôi có thể dựa vào hành vi này không? Mã sau hoạt động.

enum animal { 
    CAT = 1, 
    DOG = 2 
}; 

int y = 10; 
animal x = static_cast<animal>(y); 
+0

Tùy thuộc vào loại nguồn và đích, kết quả của static_cast có thể là hành vi không xác định, có thể bao gồm việc ném ngoại lệ. –

+1

Nó có thể là tốt hơn để hỏi, nó có thể ném một ngoại lệ trong khi chương trình đang ở trong trạng thái được xác định rõ. Tất nhiên UB về lý thuyết có thể ném một ngoại lệ, nhưng UB về mặt lý thuyết có thể định dạng ổ cứng của bạn. – Wyzard

+0

@JerryCoffin: Tiêu chuẩn 5.2.9 chỉ cho biết một số kết quả có thể không xác định và trong khi việc sử dụng tiếp theo các kết quả như vậy có thể có hành vi không xác định, không có đề cập rõ ràng về hành vi chưa được xác định từ chính diễn viên đó. Tui bỏ lỡ điều gì vậy? –

Trả lời

13

Đối với loại dàn diễn viên cụ thể này (không thể tách rời theo kiểu liệt kê), ngoại lệ có thể bị ném.

chuẩn C++ 5.2.9 cast Static [expr.static.cast] đoạn 7

Một giá trị không thể thiếu hoặc liệt kê loại có thể được chuyển đổi một cách rõ ràng để một kiểu liệt kê. Giá trị không thay đổi nếu giá trị ban đầu là trong phạm vi giá trị điều tra (7.2). Nếu không, giá trị điều tra kết quả là không xác định/không xác định (kể từ C++ 17).

Lưu ý rằng kể từ khi C++ 17 chuyển đổi như vậy có thể trên thực tế dẫn đến hành vi undefined, có thể bao gồm ném một ngoại lệ.

Nói cách khác, cách sử dụng cụ thể của bạn là static_cast để nhận giá trị được liệt kê từ một số nguyên cho đến khi C++ 17 và luôn luôn tốt, nếu bạn đảm bảo rằng số nguyên thực sự đại diện cho giá trị được liệt kê hợp lệ qua một số loại thủ tục xác thực đầu vào.

Đôi khi các thủ tục xác nhận đầu vào hoàn toàn loại bỏ sự cần thiết cho một static_cast, như vậy:

animal GetAnimal(int y) 
{ 
    switch(y) 
    { 
    case 1: 
     return CAT; 
    case 2: 
     return DOG; 
    default: 
     // Do something about the invalid parameter, like throw an exception, 
     // write to a log file, or assert() it. 
    } 
} 

Đừng xem xét sử dụng một cái gì đó giống như cấu trúc trên, cho nó đòi hỏi không có phôi và mang đến cho bạn cơ hội để xử lý các trường hợp ranh giới đúng.

6

static_cast không thể ném ngoại lệ kể từ static_cast không thời gian chạy dàn diễn viên, nếu một số không thể được đúc, mã sẽ không biên dịch. Nhưng nếu nó biên dịch và truyền là xấu - kết quả là không xác định.

+2

Điều này không nhất thiết phải đúng. Nó có thể dẫn đến hành vi không xác định cho một số kết hợp của các loại nguồn và đích, và nói * hành vi không xác định có thể bao gồm ném một ngoại lệ *. –

+1

@In silico, ForEveR: bạn có thể vui lòng cung cấp một số giải thích liên quan đến khiếu nại của bạn đối với một số static_cast <> s có hành vi không xác định? Tiêu chuẩn 5.2.9 chỉ cho biết một số kết quả có thể không xác định, và trong khi việc sử dụng tiếp theo các kết quả như vậy có thể có hành vi không xác định, không có đề cập rõ ràng về hành vi * không xác định * từ bản thân diễn viên. Tui bỏ lỡ điều gì vậy? –

+0

@TonyDelroy Vâng, kết quả là không xác định, không UB, cảm ơn. – ForEveR

9

Có an toàn để giả định rằng static_cast sẽ không bao giờ ném ngoại lệ?

Không. Đối với loại do người dùng xác định, nhà xây dựng và/hoặc nhà điều hành chuyển đổi có thể ném ngoại lệ, dẫn đến hành vi được xác định rõ.

Xem xét kết quả của chương trình này: (. Câu trả lời này chỉ tập trung vào các int để enum chuyển đổi trong câu hỏi của bạn)

#include <iostream> 

struct A { 
    A(int) { throw 1; } 
}; 

int main() { 
    int y = 7; 
    try { 
    static_cast<A>(y); 
    } catch(...) { 
    std::cout << "caught\n"; 
    } 
} 
3

Đối với một int để Enum dàn diễn viên, một ngoại lệ là không được ném ngay cả khi nó không hợp lệ. Tôi có thể dựa vào hành vi này không? Mã sau hoạt động.

enum animal { CAT = 1, DOG = 2 }; 
int y = 10; 
animal x = static_cast<animal>(y); 

Trên thực tế, sự đếm không bị giới hạn vào danh sách các kiểu liệt kê trong định nghĩa của họ, và đó không phải chỉ là một số những đứa lạ, nhưng một đặc điểm cố tình sử dụng enums - xem xét mức độ giá trị liệt kê thường ORed với nhau để đóng gói chúng thành một giá trị duy nhất hoặc giá trị 0 được chuyển khi không có liệt kê nào.

Trong C++ 03, nó không nằm dưới sự kiểm soát lập trình rõ ràng như thế nào một số nguyên sao lưu sẽ được trình biên dịch sử dụng, nhưng phạm vi được đảm bảo khoảng 0 và liệt kê liệt kê rõ ràng.

Vì vậy, không nhất thiết đúng là 10 không phải là giá trị có thể lưu trữ hợp lệ cho số animal. Ngay cả khi giá trị sao lưu không đủ lớn để lưu trữ giá trị tích phân bạn đang cố gắng chuyển đổi sang animal, có thể áp dụng chuyển đổi thu hẹp - thường thì điều này sẽ sử dụng nhiều bit quan trọng nhất mà kiểu sao lưu có thể giữ, loại bỏ bất kỳ bit thứ tự cao bổ sung nào, nhưng để biết chi tiết, hãy kiểm tra Chuẩn. Trong thực tế, hầu hết các trình biên dịch C++ 03 hiện đại trên PC và phần cứng máy chủ mặc định sử dụng (32 bit) int để quay lại điều tra, điều này tạo điều kiện cho các hàm trong thư viện C trong đó 32 bit là chuẩn.

Tôi sẽ không bao giờ mong đợi một trình biên dịch để ném ngoại lệ khi bất kỳ giá trị nào được shoehorned vào một enum sử dụng static_cast<>.

Các vấn đề liên quan