5

Vì vậy, tôi đã viết một số mã và tôi nhận thấy rằng ngoài lỗi cú pháp, loại và các lỗi biên dịch khác, C++ không ném bất kỳ ngoại lệ nào khác. Vì vậy, tôi quyết định thử nghiệm này ra với một chương trình rất tầm thường:Xử lý ngoại lệ C++

#include<iostream> 

int main() { 
    std::count<<5/0<<std::endl; 
return 1 
} 

Khi tôi biên soạn nó bằng cách sử g ++, g ++ đã cho tôi một cảnh báo nói rằng tôi đã được chia cho 0. Nhưng nó vẫn biên dịch mã. Sau đó, khi tôi chạy nó, nó in một số số tùy ý thực sự lớn. Khi tôi muốn biết là, C++ đối phó với các ngoại lệ như thế nào? Phân chia số nguyên bằng 0 phải là một ví dụ rất nhỏ khi một ngoại lệ nên được ném và chương trình sẽ chấm dứt.

Tôi có phải chủ yếu bao gồm toàn bộ chương trình của mình trong một khối thử lớn và sau đó bắt một số ngoại lệ nhất định không? Tôi biết trong Python khi một ngoại lệ được ném, chương trình sẽ ngay lập tức chấm dứt và in ra lỗi. C++ làm gì? Có ngay cả trường hợp ngoại lệ thời gian chạy mà dừng thực hiện và giết chương trình?

Trả lời

8

Có các ngoại lệ thời gian chạy, nhưng không phải mọi thứ có kết quả "sai" trong ngoại lệ thời gian chạy bị ném. Ví dụ, acccessing một mảng ngoài giới hạn hoặc dereferencing một con trỏ null chỉ đơn giản là "hành vi không xác định" - có nghĩa là bất cứ điều gì ở tất cả có thể xảy ra. Phân chia theo số không cũng rơi vào danh mục "không xác định".

Lý do cơ bản cho một số hoạt động dẫn đến "hành vi không xác định" thay vì ngoại lệ là hiệu quả. Giả sử một truy cập mảng ngoài giới hạn yêu cầu một ngoại lệ được ném ra. Sau đó trình biên dịch sẽ phải tạo mã cho mỗi truy cập mảng để kiểm tra xem nó có nằm ngoài giới hạn hay không và nếu có, hãy ném một ngoại lệ. Đó là rất nhiều kiểm tra, hầu hết trong số đó là không cần thiết. Thay vào đó, những gì trình biên dịch làm chỉ là tạo ra lệnh cho truy cập phần tử giả sử nó nằm trong giới hạn. Nếu nó xảy ra ngoài ranh giới, thì bất cứ điều gì xảy ra (ví dụ: lỗi phân đoạn) xảy ra. Nếu bạn muốn kiểm tra được thực hiện, bạn luôn có thể viết mã một cách rõ ràng.

Điều này làm cho C++ mạnh hơn các ngôn ngữ luôn kiểm tra (ví dụ: Java hoặc python) vì bạn có thể chọn thời điểm bạn muốn kiểm tra và khi nào bạn không thực hiện. (Mặt khác, nó làm cho C++ kém an toàn hơn so với Java hoặc python. Đó là một sự đánh đổi).


Đối với những gì xảy ra khi một ngoại lệ được ném nhưng không bắt được bất cứ nơi nào, thường triển khai biên dịch sẽ in một thông báo lỗi chứa của what() ngoại lệ. Trong ví dụ của bạn không áp dụng được vì không có ngoại lệ thời gian chạy nào bị ném.

+0

Cảm ơn điều đó có ý nghĩa. Một câu hỏi khác. Nếu thay vì sử dụng std :: cout, tôi sử dụng std :: cerr, điều này sẽ ném một ngoại lệ, hoặc chỉ in dòng lỗi? Và nếu tôi tạo ra ngoại lệ của riêng mình (cho phép nói foo) và trong mã của tôi tôi nói ném foo, chương trình của tôi sẽ bị giết ngay lập tức và foo.what() được in ra? Hay tôi phải nói rõ ràng C++ để làm như vậy? – user1413793

+0

@ user1413793: Nếu bạn viết thư cho 'std :: cerr', nó sẽ chỉ in ra dòng lỗi. Bạn có thể gửi luồng đầu ra và luồng lỗi tới các vị trí khác nhau thông qua chuyển hướng trên dòng lệnh ('>' vs '2>'). Nếu bạn 'ném' một ngoại lệ, và bạn không bắt được nó ở bất cứ đâu, chương trình sẽ chấm dứt ngay lập tức và in một thông báo lỗi. (Chính xác hơn, một hàm gọi là 'std :: terminate' sẽ được gọi, có hành vi mặc định là chấm dứt chương trình và in thông điệp của exception. Bạn có thể ghi đè hành vi bằng cách gọi' std :: set_terminate'. quan tâm.) – HighCommander4

0

Visual C++ gắn cờ chính xác giá trị này dưới dạng sai số chia cho 0. Vì vậy, nếu nó không biên dịch, thì không có vấn đề gì khi chạy nó.

+0

Nhưng là nó "đúng" theo tiêu chuẩn? Chỉ tò mò thôi. –

+0

Chia cho số không là không xác định ngay cả trước bất kỳ tiêu chuẩn nào, đúng không? – Superman

3

Có, có các ngoại lệ thời gian chạy. Ví dụ là out_of_range, được ném bởi vector::at.

Tuy nhiên, phép chia cho không là undefined (C++ 0x §5.6/4):

Nếu toán hạng thứ hai của/hoặc% là zero hành vi được unde fi Ned.

Vì vậy, không thể biên dịch, ném ngoại lệ được tạo sẵn, in "một số số tùy ý thực sự lớn" hoặc segfault.

+0

Ok cảm ơn! Tôi đã chỉ bối rối bởi vì các ngôn ngữ khác ném một ngoại lệ nhưng điều đó có ý nghĩa :) – user1413793

2

C++ chỉ ném ngoại lệ tiêu chuẩn được xác định rõ trong tiêu chuẩn C++.(Có nó bao gồm một số ngoại lệ thời gian chạy)

Một Integer chia cho zero không phải là một ngoại lệ C++ chuẩn (Về mặt kỹ thuật nó là Không xác định hành vi). Vì vậy, không có ngoại lệ tiềm ẩn sẽ được ném. Một trình biên dịch cụ thể có thể ánh xạ lỗi thời gian chạy tới một kiểu ngoại lệ (Bạn sẽ cần kiểm tra tài liệu biên dịch cho điều này, một số bản đồ biên dịch chia cho số không thành một ngoại lệ), nếu bạn có thể bắt được ngoại lệ đó. Tuy nhiên, lưu ý rằng đây không phải là hành vi di động và sẽ không hoạt động đối với tất cả các trình biên dịch.

Tốt nhất bạn có thể làm là kiểm tra tình trạng lỗi (số chia bằng 0) và ném ngoại lệ một cách rõ ràng trong các trường hợp như vậy.

EDIT: Để trả lời các bình luận

class A 
{ 
    public: 
     void f() 
     { 
      int x; 
      //For illustration only 
      int a = 0; 
      if(a == 0) 
        throw std::runtime_error("Divide by zero Exception"); 
      x=1/a; 
     } 

     A() 
     { 
       try 
       { 
        f(); 
       } 
       catch(const std::runtime_error& e) 
       { 
        cout << "Exception caught\n"; 
        cout << e.what(); 
       } 
     } 
};  
+0

Sẽ ném ngoại lệ gây ra các chương trình chấm dứt và có ngoại lệ in ra, hoặc tôi phải sau đó bắt sau đó ngoại lệ và rõ ràng nói với C + + phải làm gì? – user1413793

+1

@ user1413793: Cập nhật câu trả lời.Bạn sẽ phải nắm bắt ngoại lệ và quyết định phải làm gì với nó. –