Bạn nên sử dụng cả hai. Các xác nhận là để thuận tiện cho bạn như là một nhà phát triển. Ngoại lệ bắt những thứ bạn bỏ lỡ hoặc không mong đợi trong thời gian chạy.
Tôi đã yêu thích các chức năng báo cáo lỗi của glib thay vì các xác nhận cũ đơn giản. Họ hành xử như những tuyên bố khẳng định nhưng thay vì tạm dừng chương trình, họ chỉ trả lại một giá trị và để chương trình tiếp tục. Nó hoạt động tốt một cách đáng ngạc nhiên, và như một phần thưởng bạn có thể thấy những gì xảy ra với phần còn lại của chương trình của bạn khi một chức năng không trả về "những gì nó được cho là". Nếu nó gặp sự cố, bạn biết rằng việc kiểm tra lỗi của bạn bị lỏng lẻo ở một nơi khác.
Trong dự án cuối cùng của tôi, tôi đã sử dụng các kiểu hàm này để thực hiện kiểm tra điều kiện tiên quyết và nếu một trong số chúng thất bại, tôi sẽ in dấu vết ngăn xếp vào tệp nhật ký nhưng tiếp tục chạy. Tiết kiệm cho tôi hàng tấn thời gian gỡ lỗi khi người khác gặp sự cố khi chạy bản dựng gỡ lỗi của tôi.
#ifdef DEBUG
#define RETURN_IF_FAIL(expr) do { \
if (!(expr)) \
{ \
fprintf(stderr, \
"file %s: line %d (%s): precondition `%s' failed.", \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
#expr); \
::print_stack_trace(2); \
return; \
}; } while(0)
#define RETURN_VAL_IF_FAIL(expr, val) do { \
if (!(expr)) \
{ \
fprintf(stderr, \
"file %s: line %d (%s): precondition `%s' failed.", \
__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
#expr); \
::print_stack_trace(2); \
return val; \
}; } while(0)
#else
#define RETURN_IF_FAIL(expr)
#define RETURN_VAL_IF_FAIL(expr, val)
#endif
Nếu tôi cần kiểm tra thời gian chạy đối số, tôi sẽ làm điều này:
char *doSomething(char *ptr)
{
RETURN_VAL_IF_FAIL(ptr != NULL, NULL); // same as assert(ptr != NULL), but returns NULL if it fails.
// Goes away when debug off.
if( ptr != NULL )
{
...
}
return ptr;
}