Tiêu chuẩn C++ chống định nghĩa assert
theo tiêu chuẩn C.
C99 §7.2/2:
” Các assert
vĩ mô đặt xét nghiệm chẩn đoán vào các chương trình; nó mở rộng thành một biểu thức void. Khi nó được thực hiện, nếu biểu thức (phải có loại vô hướng) là sai (nghĩa là, so sánh bằng 0), macro khẳng định ghi thông tin về cuộc gọi cụ thể không thành công (bao gồm văn bản của đối số, tên của tệp nguồn, số dòng nguồn và tên của hàm kèm theo - sau này tương ứng với các giá trị của các macro tiền xử lý __FILE__
và __LINE__
và số nhận dạng __func__
) trên tệp lỗi chuẩn theo định dạng được xác định. Sau đó, nó gọi hàm abort
.
Trong assert(0)
các 0
được hiểu như là false
, vì vậy sự khẳng định này sẽ luôn luôn thất bại, hoặc lửa, khi kiểm tra khẳng định là trên.
Do đó nó khẳng định rằng
“ Việc thực hiện sẽ không bao giờ đạt đến điểm này. ”
Thực tế, khó có thể làm cho trình biên dịch đóng cửa khi thực hiện đạt hoặc không đạt đến điểm đã cho. Thông thường trình biên dịch đầu tiên sẽ phàn nàn về việc thực hiện có thể đạt đến kết thúc của một hàm mà không trả về một giá trị. Thêm assert(0)
lý tưởng nên giải quyết vấn đề đó, nhưng sau đó trình biên dịch có thể khiếu nại về số assert
hoặc không nhận ra rằng nó cho biết bạn đã biết rõ những gì nó cố cảnh báo.
Một (1) biện pháp có thể sau đó cũng để ném một ngoại lệ tại thời điểm đó:
auto foo(int x)
-> int
{
if(x == 1) { return 42; }
assert(0); throw 0; // Should never get here!
}
Tất nhiên rằng đôi whammy có thể được định nghĩa là một cấp độ vĩ mô cao hơn. Về loại ngoại lệ, bạn có thể muốn giữ nó như không phải là std::exception
, bởi vì đây không phải là một ngoại lệ có ý định bị bắt bởi một số catch
thông thường ở bất kỳ đâu.Hoặc, nếu bạn tin tưởng vào hệ thống phân cấp ngoại lệ tiêu chuẩn (nó không có ý nghĩa với tôi, nhưng) bạn có thể sử dụng một std::logic_error
.
Để tắt assert
khẳng định việc kiểm tra, bạn có thể xác định biểu tượng NDEBUG
trước bao gồm <assert.h>
.
Tiêu đề này có hỗ trợ đặc biệt để bạn có thể bao gồm nhiều lần, có hoặc không có NDEBUG
được xác định.
C++ 11 §17.6.2.2/2:
” Một đơn vị dịch thuật có thể bao gồm tiêu đề thư viện trong bất kỳ thứ tự (khoản 2). Mỗi lần có thể được bao gồm nhiều hơn một lần, không có hiệu lực khác với việc được bao gồm chính xác một lần, ngoại trừ hiệu ứng bao gồm <cassert>
hoặc <assert.h>
phụ thuộc mỗi lần theo định nghĩa từ vựng hiện tại là NDEBUG
.
Định nghĩa hợp lý về tính năng đánh lừa đôi được thảo luận ở trên có thể tương tự như vậy phụ thuộc vào NDEBUG
không có bảo vệ, ví dụ:
file
assert_should_never_get_here.hpp
#include <stdexcept> // std::logic_error
#include <assert.h>
#undef ASSERT_SHOULD_NEVER_GET_HERE
#ifdef NDEBUG
# define ASSERT_SHOULD_NEVER_GET_HERE() \
throw std::logic_error("Reached a supposed unreachable point")
#else
# define ASSERT_SHOULD_NEVER_GET_HERE() \
do{ \
assert("Reached a supposed unreachable point" && 0); \
throw 0; \
} while(0)
#endif
Disclaimer: Trong khi tôi mã đó lên một số lần trong đầu những năm 2000, tôi nấu chín lên đoạn mã trên chỉ dành riêng cho câu trả lời này, và trong khi tôi đã thử nghiệm nó với g ++ nó có thể không nhất thiết phải hoàn hảo.
(1) Xem Basile Starynkevitch's answer để thảo luận các khả năng khác, g ++ - cụ thể nội tại __builtin_unreachable
.
Sử dụng nhiều dấu chấm than: khẳng định (!!! "Điều bạn hy vọng sẽ không xảy ra. Nó vừa xảy ra"); –
Chỉ cần cẩn thận để sử dụng một số lẻ của chúng. Và xem xét nhận xét của Terry Pratchett, "Nhiều dấu chấm than", anh ta tiếp tục, lắc đầu, "là một dấu hiệu chắc chắn của một tâm trí bị bệnh". Và 3 dấu chấm than chắc chắn là "nhiều", giải pháp duy nhất chính xác là 1 Dù sao, tôi nhớ lại rằng Andrei Alexandrescu và tôi đã không đồng ý một cách tốt nhất. Andrei ủng hộ 'khẳng định (" Blah "&& condition)' trong khi tôi ủng hộ 'khẳng định ((" Blah ", điều kiện))' (cả hai chúng ta đều không ủng hộ dấu chấm than). Hôm nay tôi sử dụng '&&', bởi vì nó đơn giản hơn *, dễ dàng hơn. Nhưng đó là lý do tại sao tôi sau đó ủng hộ '(())' ... –