Những gì bạn dường như bị bắt gặp là địa ngục cụ thể của một người nào đó đang cố gắng để có bánh của họ và ăn nó.
RAII và các trường hợp ngoại lệ được thiết kế để đi đôi với nhau. RAII là phương tiện mà bạn không phải viết nhiều catch(...)
tuyên bố để dọn dẹp. Nó sẽ xảy ra tự động, như một vấn đề tất nhiên. Và các ngoại lệ là cách duy nhất để làm việc với các đối tượng RAII, bởi vì các hàm tạo chỉ có thể thành công hoặc ném (hoặc đặt đối tượng ở trạng thái lỗi, nhưng ai muốn điều đó?).
Một catch
tuyên bố có thể làm một trong hai điều: xử lý lỗi hoặc hoàn cảnh đặc biệt hoặc thực hiện công việc dọn dẹp. Đôi khi nó làm cả hai, nhưng mọi catch
tuyên bố tồn tại để làm ít nhất một trong số này.
catch(...)
không có khả năng thực hiện xử lý ngoại lệ thích hợp. Bạn không biết ngoại lệ là gì; bạn không thể có được thông tin về ngoại lệ. Bạn hoàn toàn không có thông tin nào ngoài thực tế là một ngoại lệ đã bị ném bởi thứ gì đó trong một khối mã nhất định. Điều hợp pháp duy nhất bạn có thể làm trong một khối như vậy là dọn dẹp. Và điều đó có nghĩa là ném lại ngoại lệ vào cuối đợt dọn dẹp.
Những gì RAII mang lại cho bạn liên quan đến việc xử lý ngoại lệ là dọn dẹp miễn phí. Nếu mọi thứ được RAII đóng gói đúng cách, thì mọi thứ sẽ được dọn sạch. Bạn không còn cần phải có catch
tuyên bố làm sạch. Trong trường hợp đó, không có lý do để viết một catch(...)
tuyên bố.
Vì vậy, tôi đồng ý rằng catch(...)
hầu hết là xấu xa ... tạm thời .
Điều khoản đó được sử dụng đúng RAII. Bởi vì không có nó, bạn cần có khả năng dọn dẹp nhất định. Không có xung quanh nó; bạn phải có khả năng làm công việc dọn dẹp. Bạn cần có khả năng đảm bảo rằng việc ném một ngoại lệ sẽ khiến mã ở trạng thái hợp lý. Và catch(...)
là một công cụ quan trọng để làm như vậy.
Bạn không thể có cái này mà không có cái kia. Bạn không thể nói rằng cả RAII và catch(...)
đều xấu. Bạn cần ít nhất một trong số này; mặt khác, bạn không phải là ngoại lệ an toàn.
Tất nhiên, có một cách sử dụng hợp lệ mặc dù hiếm khi catch(...)
mà RAII không thể loại bỏ: nhận được một exception_ptr
chuyển tiếp cho người khác. Thông thường thông qua một promise/future
giao diện hoặc tương tự.
Đồng nghiệp của tôi nói rằng bạn phải luôn biết những ngoại lệ nào sẽ bị ném và bạn luôn có thể sử dụng các cấu trúc như:
Đồng nghiệp của bạn là một thằng ngốc (hoặc chỉ là không biết gì khủng khiếp). Điều này cần phải rõ ràng ngay lập tức do có bao nhiêu mã sao chép và dán mà anh ấy đề nghị bạn viết. Việc dọn dẹp cho mỗi câu lệnh khai thác sẽ hoàn toàn giống nhau . Đó là một cơn ác mộng bảo trì, chưa kể đến khả năng đọc.
Nói tóm lại: đây là vấn đề mà RAII được tạo ra để giải quyết (không phải là nó không giải quyết được các vấn đề khác).
Điều khiến tôi bối rối về khái niệm này là nó thường ngược với cách mà hầu hết mọi người cho rằng RAII là xấu. Nói chung, lập luận "RAII rất tệ vì bạn phải sử dụng ngoại lệ để báo hiệu lỗi nhà xây dựng. Nhưng bạn không thể ném ngoại lệ, vì nó không an toàn và bạn sẽ phải có nhiều catch
tuyên bố để dọn dẹp mọi thứ." Đó là một đối số bị phá vỡ vì RAII giải quyết vấn đề mà sự thiếu RAII tạo ra.
Nhiều khả năng, anh ta chống lại RAII vì nó che giấu chi tiết. Các cuộc gọi hủy không hiển thị ngay lập tức trên các biến tự động. Vì vậy, bạn nhận được mã được gọi ngầm. Một số lập trình viên thực sự ghét điều đó. Rõ ràng, đến mức họ nghĩ rằng có 3 catch
câu lệnh, tất cả đều làm điều tương tự với mã sao chép và dán là một ý tưởng tốt hơn.
...
" trong khi câu hỏi của tôi tập trung vào "Tôi nên bắt tốt hơn...
hay<specific exception>
trước khi suy nghĩ lại"