Nguyên tắc cốt lõi C ++ có quy tắc ES.20: Luôn khởi tạo một đối tượng .
Tránh các lỗi được sử dụng trước khi đặt và hành vi không xác định liên quan của chúng. Tránh các vấn đề với sự hiểu biết về khởi tạo phức tạp. Đơn giản hóa tái cấu trúc.
Nhưng quy tắc này không giúp tìm ra lỗi, nó chỉ che giấu chúng.
Giả sử rằng một chương trình có một đường dẫn thực thi trong đó nó sử dụng một biến chưa được khởi tạo. Đây là một lỗi. Hành vi không xác định sang một bên, điều đó cũng có nghĩa là đã xảy ra sự cố và chương trình có thể không đáp ứng yêu cầu sản phẩm của nó. Khi nó sẽ được triển khai để sản xuất, có thể mất tiền, hoặc thậm chí tệ hơn.
Làm thế nào để chúng tôi sàng lọc lỗi? Chúng tôi viết bài kiểm tra. Nhưng các bài kiểm tra không bao gồm 100% đường dẫn thực hiện và các bài kiểm tra không bao giờ bao gồm 100% các đầu vào chương trình. Hơn thế nữa, ngay cả một bài kiểm tra bao gồm một đường dẫn thực thi bị lỗi - nó vẫn có thể vượt qua. Cuối cùng, đó là hành vi không xác định, một biến chưa được khởi tạo có thể có giá trị hợp lệ.
Nhưng ngoài các thử nghiệm của chúng tôi, chúng tôi có các trình biên dịch có thể viết một cái gì đó như 0xCDCDCDCD cho các biến chưa được khởi tạo. Điều này hơi cải thiện tỷ lệ phát hiện của các xét nghiệm.
Thậm chí tốt hơn - có các công cụ như Trình khử trùng địa chỉ, sẽ bắt tất cả các lần đọc các byte bộ nhớ chưa được khởi tạo.
Và cuối cùng, có các máy phân tích tĩnh, có thể nhìn vào chương trình và cho biết rằng có một giá trị đọc trước được đặt trên đường dẫn thực thi đó.
Vì vậy, chúng tôi có nhiều công cụ mạnh mẽ, nhưng nếu chúng tôi khởi tạo biến - chất khử trùng không tìm thấy gì .
int bytes_read = 0;
my_read(buffer, &bytes_read); // err_t my_read(buffer_t, int*);
// bytes_read is not changed on read error.
// It's a bug of "my_read", but detection is suppressed by initialization.
buffer.shrink(bytes_read); // Uninitialized bytes_read could be detected here.
// Another bug: use empty buffer after read error.
use(buffer);
Có một quy tắc khác - nếu thực thi chương trình gặp lỗi, chương trình sẽ chết càng sớm càng tốt. Không cần phải giữ cho nó sống, chỉ cần sụp đổ, viết một vụ tai nạn, đưa nó cho các kỹ sư để điều tra.
Việc khởi tạo các biến không cần thiết sẽ làm ngược lại - chương trình đang được giữ nguyên, khi đó nó sẽ bị lỗi phân đoạn.
\0
lỗi. Nếu nó được ghi nhận là không giải quyết điều đó, mã cuộc gọi của bạn bị lỗi. Nếu bạn sửa mã cuộc gọi của mình để kiểm tra bytes_read==0
trước khi gọi sử dụng, thì bạn sẽ quay lại nơi bạn đã bắt đầu: mã của bạn bị lỗi nếu bạn không khởi tạo bytes_read
, an toàn nếu bạn thực hiện. ( Thông thường các hàm được cho là điền vào các tham số ngoài của chúng ngay cả trong trường hợp có lỗi : không thực sự. Thông thường, các đầu ra thường bị bỏ lại một mình hoặc không xác định.)
err_t
trả lại bởi my_read()
? Nếu có một lỗi ở bất cứ đâu trong ví dụ, thì đó là.
bytes_read
không được thay đổi (vì vậy giữ nguyên số 0), tại sao điều này được coi là lỗi? Chương trình vẫn có thể tiếp tục một cách lành mạnh miễn là nó không hoàn toàn mong đợibytes_read!=0
sau đó. Vì vậy, nó là vệ sinh tốt không phàn nàn. Mặt khác, khibytes_read
không được khởi tạo trước, chương trình sẽ không thể tiếp tục một cách lành mạnh, do đó, không khởi tạobytes_read
thực sự đưa ra một lỗi không có trước đó.