Tôi nhận ra rằng trong khi câu hỏi không có thẻ ngôn ngữ, có lẽ nó đang ngầm nói về ngôn ngữ cà phê của cà phê. Nhưng chỉ để hoàn thiện, tôi muốn đề cập đến sự đồng thuận rõ ràng có phần khác biệt trong thế giới C ++.
Có ba điều mà các lập trình viên C ++ thường sẽ quan tâm:
- Nó sẽ có chi phí không trong các bản dựng được tối ưu hóa? (Có nghĩa là, nó có thể được biên soạn ra ra không?)
- Tôi có thể sử dụng nó để bẫy vào trình gỡ lỗi ngay tại điểm phát hiện lỗi không?
- Tôi có thể sử dụng nó để báo cáo các vấn đề từ các chức năng được khai báo
noexcept
không?
Trước đây, tôi đã tiếp cận vấn đề đầu tiên bằng cách viết mã như thế này
int
factorial(const int n)
{
if (CHECK_ARGS)
{
if (n < 0)
throw std::invalid_argument {"n < 0"};
}
int fac = 1;
for (int i = 2; i <= n; ++i)
fac *= i;
return fac;
}
trong đó d CHECK_ARGS
là #define
hằng số thời gian biên dịch để trình biên dịch có thể loại bỏ hoàn toàn tất cả mã kiểm tra đối số trong các bản dựng được tối ưu hóa. (Tôi không nói rằng việc biên dịch séc là một điều tốt nói chung nhưng tôi tin rằng người dùng nên có tùy chọn để biên dịch chúng.)
Tôi vẫn thích về giải pháp này rằng mã kiểm tra đối số được hiển thị rõ ràng được nhóm lại với nhau thành if
. Tuy nhiên, vấn đề thứ hai và thứ ba không được giải quyết bằng cách này. Do đó, giờ đây tôi lại nghiêng về việc sử dụng assert
macro để kiểm tra đối số.
Các tiêu chuẩn mã hóa Boost đồng ý với điều này:
Lỗi lập trình viên thì sao?
Là một nhà phát triển, nếu tôi đã vi phạm điều kiện tiên quyết của thư viện tôi đang sử dụng, tôi không muốn ngăn xếp ngăn xếp. Những gì tôi muốn là một bãi chứa cốt lõi hoặc tương đương - một cách để kiểm tra trạng thái của chương trình tại điểm chính xác nơi phát hiện sự cố. Điều đó thường có nghĩa assert()
hoặc một cái gì đó giống như nó.
Có một cuộc nói chuyện rất thú vị được đưa ra bởi John Lakos tại CppCon'14 có tiêu đề Lập trình phòng thủ được thực hiện đúng ( phần 1 , phần 2 ). Trong phần đầu tiên của bài nói chuyện, ông thảo luận về lý thuyết hợp đồng và hành vi không xác định. Trong phần thứ hai, ông trình bày những gì tôi cho là một đề xuất rất tốt để kiểm tra lập luận có hệ thống. Về bản chất, ông đề xuất các macro xác nhận cho phép người dùng chọn bao nhiêu ngân sách (về mức độ sử dụng CPU) mà cô sẵn sàng quyên góp cho thư viện để kiểm tra đối số và thư viện sử dụng ngân sách đó một cách khôn ngoan. Ngoài ra, người dùng cũng có thể cài đặt chức năng xử lý lỗi toàn cầu sẽ được gọi trong trường hợp phát hiện hợp đồng bị hỏng.
Về khía cạnh của một chức năng là riêng tư, tôi không nghĩ rằng điều này có nghĩa là chúng ta không bao giờ nên kiểm tra các đối số của nó. Chúng tôi có thể tin tưởng mã riêng của mình nhiều hơn để không vi phạm hợp đồng của một chức năng nội bộ nhưng chúng tôi cũng biết rằng chúng tôi cũng không hoàn hảo. Kiểm tra đối số trong các chức năng nội bộ cũng hữu ích trong việc phát hiện các lỗi của chúng ta cũng như trong các chức năng công cộng để phát hiện các lỗi trong mã máy khách.