Sự khác biệt: std :: runtime_error so với std :: ngoại lệ ()


127

Sự khác biệt giữa std::runtime_errorvà là std::exceptiongì? Việc sử dụng thích hợp cho mỗi là gì? Tại sao chúng khác nhau ở nơi đầu tiên?

Câu trả lời:


152

std::exceptionlà lớp có mục đích duy nhất là đóng vai trò là lớp cơ sở trong hệ thống phân cấp ngoại lệ. Nó không có công dụng khác. Nói cách khác, về mặt khái niệm nó là một thứ trừu tượng lớp (mặc dù nó không được định nghĩa là lớp trừu tượng theo nghĩa C ++ của thuật ngữ này).

std::runtime_errorlà một lớp chuyên biệt hơn, giảm dần từ std::exception, dự định được ném trong trường hợp có nhiều lỗi thời gian chạy . Nó có một mục đích kép. Nó có thể bị ném bởi chính nó hoặc nó có thể đóng vai trò là lớp cơ sở cho các loại ngoại lệ lỗi thời gian chạy chuyên dụng khác nhau, chẳng hạn như std::range_error, std::overflow_errorv.v. Bạn có thể định nghĩa các lớp ngoại lệ của riêng mình giảm dần std::runtime_error, cũng như bạn có thể xác định ngoại lệ của riêng mình các lớp giảm dần từ std::exception.

Cũng giống như std::runtime_error, thư viện tiêu chuẩn chứa std::logic_error, cũng giảm dần std::exception.

Điểm có hệ thống phân cấp này là cung cấp cho người dùng cơ hội sử dụng toàn bộ sức mạnh của cơ chế xử lý ngoại lệ C ++. Vì mệnh đề 'bắt' có thể bắt ngoại lệ đa hình, người dùng có thể viết các mệnh đề 'bắt' có thể bắt các loại ngoại lệ từ một cây con cụ thể của hệ thống phân cấp ngoại lệ. Ví dụ: catch (std::runtime_error& e)sẽ bắt tất cả các ngoại lệ từ std::runtime_errorcây con, cho phép tất cả những người khác đi qua (và bay xa hơn lên ngăn xếp cuộc gọi).

PS Thiết kế một hệ thống phân cấp lớp ngoại lệ hữu ích (sẽ chỉ cho phép bạn nắm bắt các loại ngoại lệ mà bạn quan tâm tại mỗi điểm của mã của bạn) là một nhiệm vụ không hề nhỏ. Những gì bạn thấy trong thư viện C ++ tiêu chuẩn là một cách tiếp cận khả thi, được cung cấp cho bạn bởi các tác giả của ngôn ngữ. Như bạn thấy, họ đã quyết định chia tất cả các loại ngoại lệ thành "lỗi thời gian chạy" và "lỗi logic" và cho phép bạn tiến hành từ đó với các loại ngoại lệ của riêng bạn. Tất nhiên, có những cách khác để cấu trúc hệ thống phân cấp đó, có thể phù hợp hơn trong thiết kế của bạn.

Cập nhật: Tính di động Linux vs Windows

Như Loki Astari và unixman83 đã lưu ý trong câu trả lời và nhận xét của họ bên dưới, hàm tạo của exceptionlớp không nhận bất kỳ đối số nào theo tiêu chuẩn C ++. Microsoft C ++ có một hàm tạo lấy các đối số trong exceptionlớp, nhưng điều này không chuẩn. Các runtime_errorlớp học có một đối số constructor lấy ( char*) trên cả hai nền tảng Windows và Linux. Để được xách tay, sử dụng tốt hơn runtime_error.

(Và hãy nhớ, chỉ vì một đặc điểm kỹ thuật của dự án của bạn nói rằng mã của bạn không phải chạy trên Linux, điều đó không có nghĩa là nó không bao giờ phải chạy trên Linux.)


1
cảm ơn bạn. câu trả lời chính xác. mặc dù tôi tự hỏi liệu có bao giờ cần phải có loại ngoại lệ khác không ... chỉ là một ý nghĩ.
sivabudh

1
Nếu có khả năng ngoại lệ có thể được bao phủ lại, thì một loại ngoại lệ khác có thể hữu ích vì chúng ta có thể sử dụng cơ chế xử lý ngoại lệ để hướng ngoại lệ đến xử lý sẽ cố gắng khắc phục sự cố. Nếu không có cơ hội phục hồi hơn một trong những trường hợp ngoại lệ tiêu chuẩn là tốt.
Martin York

1
Chỉ là một bên: không có quy tắc, bất cứ nơi nào, buộc bạn phải xuất phát từ std::exception. Chắc chắn, tất cả stdmọi thứ ném các lớp dẫn xuất của điều đó, nhưng hoàn toàn không có lý do để chỉ ném std::exceptioncác đối tượng dẫn xuất.
rubenvb

1
@rubenvb Tôi không biết về điều đó, nhưng tôi nghĩ nó sẽ làm rõ mã để bảo trì trong tương lai nếu chỉ các đối tượng của các lớp xuất phát từ ngoại lệ được ném ra. Ví dụ: Tôi muốn tìm hiểu những ngoại lệ tùy chỉnh nào được triển khai trong cơ sở mã của tôi và tìm kiếm các lớp xuất phát từ ngoại lệ.
this.myself

21

std::exceptionnên được xem xét (lưu ý xem xét) cơ sở trừu tượng của hệ thống phân cấp ngoại lệ tiêu chuẩn. Điều này là do không có cơ chế chuyển trong một thông điệp cụ thể (để làm điều này, bạn phải lấy được và chuyên môn hóa what()). Không có gì ngăn bạn sử dụng std :: ngoại lệ và đối với các ứng dụng đơn giản, đó có thể là tất cả những gì bạn cần.

std::runtime_errormặt khác có các hàm tạo hợp lệ chấp nhận một chuỗi dưới dạng một thông điệp. Khi what()được gọi là một con trỏ const char được trả về, các điểm tại một chuỗi C có cùng chuỗi như được truyền vào hàm tạo.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 

1
Cảm ơn câu trả lời martin. Tuy nhiên, tôi sử dụng std :: exe () giống như cách bạn mô tả ở trên. tức là hàm tạo std :: exe () cũng có thể lấy std :: string () hoặc const char *.
sivabudh

14
Không theo tiêu chuẩn. std :: ngoại lệ có một hàm tạo không có đối số. Sử dụng phiên bản chấp nhận chuỗi std :: hoặc C-String là không khả dụng.
Martin York

10
Vì Microsoft, tôi đã quen với việc ném std::exception(std::string). Bây giờ tôi nhận ra rằng tôi phải ném std::runtime_errornếu tôi muốn mã của mình hoạt động trong Linux (GCC).
unixman83
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.