2010-09-29 35 views
26

Điều này đã trở thành một trong các nhận xét đánh giá mã.NULL kiểm tra trước khi xóa một đối tượng có quá tải xóa

Bạn có nên kiểm tra NULL trước khi gọi xóa cho bất kỳ đối tượng nào không?

Tôi hiểu xóa kiểm tra toán tử cho NULL nội bộ và dư thừa nhưng đối số được đưa ra là xóa khi toán tử có thể bị quá tải và nếu phiên bản quá tải không kiểm tra NULL nó có thể bị lỗi. Vì vậy, nó là an toàn và hợp lý để giả định rằng nếu và khi xóa sẽ bị quá tải nó sẽ kiểm tra cho NULL hay không? Trong sự hiểu biết của tôi hợp lý của nó để giả định trường hợp đầu tiên mà quá tải xóa sẽ chăm sóc kiểm tra NULL, và điểm đánh giá không giữ tốt. Bạn nghĩ sao?

+7

Hah. Dường như không ai (kể cả tôi) đọc câu hỏi đầy đủ trước khi trả lời. –

+3

@Konrad - :) Hãy cho chúng tôi biết những người háo hức muốn giúp đỡ như thế nào. Đây là trang web tuyệt vời. Yêu nó! –

+0

xem liên quan: http://stackoverflow.com/questions/1265666/reason-why-not-to-have-a-delete-macro-for-c – moala

Trả lời

35

Không, đừng kiểm tra giá trị rỗng. Tiêu chuẩn nói rằng delete (T*)0; là hợp lệ. Nó sẽ chỉ làm phức tạp mã của bạn vì không có lợi ích. Nếu operator delete bị quá tải thì tốt hơn nên kiểm tra null trong quá trình thực thi toán tử. Chỉ cần lưu các dòng mã và lỗi.

EDIT: Câu trả lời này đã được chấp nhận và upvoted, tuy nhiên, theo ý kiến ​​của tôi, nó không phải là rất nhiều thông tin. Có một phần còn thiếu trong tất cả các câu trả lời ở đây, và, vì lợi ích lương tâm, hãy để tôi thêm phần cuối cùng này ở đây.

Các tiêu chuẩn thực sự nói trong [basic.stc.dynamic], ít nhất kể từ C++ 03:

Bất kỳ chức năng phân bổ và/hoặc deallocation định nghĩa trong một chương trình C++, bao gồm các phiên bản mặc định trong thư viện, phù hợp với ngữ nghĩa được quy định trong 3.7.4.1 và 3.7.4.2.

Trường hợp các phần được tham chiếu, cũng như một số địa điểm khác trong tiêu chuẩn được liệt kê trong các câu trả lời khác, nói rằng ngữ nghĩa của việc truyền con trỏ null là no-op.

+1

do đó, điều đó có nghĩa là trường hợp quá tải 'toán tử xóa' trách nhiệm của phù hợp với tiêu chuẩn nằm trong việc thực hiện các nhà điều hành? tức là nếu nó không kiểm tra NULL thì nó không phù hợp với tiêu chuẩn? – Naveen

+0

@Naveen - Đó là câu hỏi tôi đang cố gắng nhận được câu trả lời, Cảm ơn bạn đã mang nó ra với những từ đúng! –

+2

@Naveen @Als: Có ý nghĩa yếu. Không theo nghĩa mạnh mẽ của từ "phù hợp". Nếu bạn thực hiện thao tác xóa mà không kiểm tra NULL nó vẫn phù hợp (ví dụ: nó chỉ in 'cout << address << '\ n''). Nhưng nếu nó mang lại hành vi không xác định, đó là một lỗi trong việc thực hiện 'toán tử delete' của bạn. – ybungalobill

19

Tôi có thể nói rằng đó là một lý do để đảm bảo rằng nếu bạn quá tải operator delete, thì bạn nên luôn luôn kiểm tra số NULL, nếu không bạn sẽ vi phạm ngữ nghĩa.

7

Bạn có nên kiểm tra NULL trước khi gọi xóa cho bất kỳ đối tượng nào không?

Không!

int *p = NULL; 
delete p ; //no effect 

Tiêu chuẩn nói [Mục 5.3.5/2]

Nếu toán hạng có kiểu lớp, các toán hạng được chuyển thành một loại con trỏ bằng cách gọi hàm chuyển đổi nêu trên, và toán hạng được chuyển đổi được sử dụng thay cho toán hạng ban đầu cho phần còn lại của phần này. Trong một trong hai cách khác, nếu giá trị của toán hạng xóa là con trỏ null, thao tác này không có hiệu lực.

Hơn nữa tại Mục 18.4.1.1/13

void operator delete(void* ptr) throw();

void operator delete(void* ptr, const std::nothrow_t&) throw();

Mặc định hành vi:

- Đối với một giá trị null của ptr, không làm gì cả.

- Bất kỳ giá trị nào khác của ptr sẽ là giá trị được trả về trước đó bằng một cuộc gọi đến toán tử mặc định mới, không bị vô hiệu hóa bởi cuộc gọi đến nhà điều hành xóa (void *) (17.4.3.7). Đối với một giá trị không rỗng như vậy của ptr, reclaims lưu trữ được phân bổ bởi các cuộc gọi trước đó để các nhà điều hành mặc định mới.

EDIT:

James Kanze here nói rằng

Nó vẫn là responisiblity của operator delete (hoặc xóa []) để kiểm tra; tiêu chuẩn không đảm bảo rằng nó sẽ không được đưa ra một con trỏ null; tiêu chuẩn yêu cầu rằng nó là một no-op nếu được đưa ra một con trỏ null. Hoặc thực hiện được phép gọi nó. Theo dự thảo mới nhất, "Giá trị của đối số đầu tiên được cung cấp cho hàm deallocation có thể là giá trị con trỏ null; nếu có, và nếu hàm deallocation được cung cấp trong thư viện chuẩn, cuộc gọi không có hiệu lực." Tôi không hoàn toàn chắc chắn ý nghĩa của điều đó "là cái được cung cấp trong thư viện chuẩn" có nghĩa là --- được lấy theo nghĩa đen, vì chức năng của anh ta không phải là thư viện chuẩn, câu này dường như không áp dụng . Nhưng bằng cách nào đó, điều đó không có ý nghĩa.

+0

-1 đọc câu hỏi. – wilhelmtell

+2

@wilhelmtell: Bạn không thể thấy một ** lớn KHÔNG **? –

+0

Tôi có thể, nhưng lý do của bạn rõ ràng cho thấy bạn đã ngừng đọc ở tiêu đề của câu hỏi. OP * BIẾT * đây là một nút trong trường hợp mặc định. – wilhelmtell

3

Không cần kiểm tra null. xóa toán tử không chck cho null để kiểm tra bổ sung là không cần thiết.

3

delete (T*)0; hợp lệ và không làm gì, tương tự free(NULL); cũng hợp lệ và không làm gì cả. Nếu bạn quá tải toán tử delete, việc triển khai của bạn phải mang cùng ngữ nghĩa. Tiêu chuẩn này cho biết tiêu chuẩn delete sẽ hoạt động như thế nào, nhưng tôi không nghĩ rằng nó sẽ hoạt động như thế nào khi quá tải delete. Để phù hợp với hành vi chuẩn/mặc định, nó sẽ cho phép (T*)0 làm đầu vào.

3

Từ tài liệu chuẩn, 18.5.1.1.13 dưới delete,

Mặc định hành vi: Nếu ptr là null, không có gì. Nếu không, hãy khôi phục bộ nhớ được phân bổ bởi cuộc gọi trước đó tới toán tử mới.

Vì vậy, bạn không cần phải kiểm tra theo mặc định ..

2

Không cần phải kiểm tra NULL trước khi xóa. Nếu ai đó đã quá tải delete với thứ gì đó không hoạt động theo cách tiêu chuẩn thì đó là vấn đề thực sự.Không ai nên coi nhẹ nhiệm vụ quá tải delete và phải luôn hỗ trợ hành vi mong đợi như kiểm tra NULL và không thực hiện hành động nào.

Tuy nhiên, đối với những gì nó có giá trị, bạn nên luôn nhớ để gán zero cho bất kỳ con trỏ mà bạn vừa xóa, trừ khi ví dụ bạn muốn xóa các con trỏ cũng như:

void MyObj::reset() 
{ 
    delete impl_; 
    impl_ = 0; // Needed here - impl_ may be reused/referenced. 
} 

MyObj::~MyObj() 
{ 
    delete impl_; // No need to assign here as impl_ is going out of scope. 
} 
6

Tôi sẽ nói đó là trách nhiệm của một quá tải delete để hoạt động như bạn mong đợi delete để hoạt động. Tức là, nó nên xử lý con trỏ NULL là một no-op.

Và vì vậy, khi gọi quá trình xóa quá tải, bạn nên không kiểm tra NULL. Bạn nên dựa vào quá tải xóa để được thực hiện một cách chính xác.

0

Một chút của C++ pedantry: NULL không phải là một khái niệm được xây dựng trong. Có tất cả chúng ta đều biết ý nghĩa của nó nhưng trong C++ trước C++ 0X, khái niệm con trỏ null đơn giản là giá trị 0. NULL thường là một macro cụ thể cho nền tảng mở rộng đến 0.

Với C++ 0X chúng ta nhận nullptr mà là rõ ràng hơn một số không đồng bằng và không thể chuyển đổi sang bất kỳ loại tích phân nào ngoại trừ bool, và là một khái niệm tốt hơn NULL (hoặc có lẽ thực hiện tốt hơn khái niệm đằng sau NULL).

+2

Ngoài ra, rất nhiều C++ pedantry: một con trỏ null là giá trị "một con trỏ null", không (nhất thiết) giá trị 0, mà là một số nguyên, không phải là một con trỏ. Khi được chuyển thành kiểu con trỏ, biểu thức số nguyên * hằng số có giá trị 0 dẫn đến con trỏ null (và do đó được gọi là hằng số null), nhưng đó là trường hợp đặc biệt được xác định trong tiêu chuẩn. –

+0

Cũng vì cách duy nhất để xác định con trỏ null thông qua ngôn ngữ trước C++ 0X là sử dụng giá trị hằng số bằng 0 và kết quả là gọi quá tải số nguyên chứ không phải quá tải con trỏ, đó là REALLY pedantic, -) –

+0

Có nhiều cách khác để có được một con trỏ null. Ví dụ, 'std :: strstr (" a "," b ");'. Rõ ràng, sử dụng hằng số con trỏ null là cách * hợp lý *. Tiền thưởng của tôi chỉ là để chỉ ra rằng có một sự khác biệt giữa '0' (một số nguyên, và một hằng số con trỏ null, và một giá trị có thể cho NULL) so với' (char *) 0' hoặc '(void *) 0' (cả hai con trỏ null, và cả hai hằng số null con trỏ, nhưng không phải là hợp pháp cho NULL trong C++). –

2

Có phải không cần thiết để kiểm tra. Nếu bất cứ ai quá tải pethod, là trách nhiệm của mình để bất cứ điều gì với NULL.

1

Tôi sẽ nói các câu hỏi có chứa thông tin không đầy đủ. Cửa hàng của tôi vẫn có một kiểm tra cho NULL trước khi xóa trong tiêu chuẩn mã hóa của chúng tôi, vì chúng tôi vẫn có một cấu hình trình biên dịch/nền tảng mà chúng tôi phải hỗ trợ mà đi vào hành vi không xác định với toán tử xóa defualt nếu nó được truyền NULL. Nếu poster gốc có tình huống tương tự thì có một điểm để kiểm tra NULL, nếu không, thay đổi tiêu chuẩn mã hóa!

+0

Xin lỗi, Không nền tảng nào của tôi không có giới hạn nào như vậy, nhưng giả sử một người viết luôn thực hiện xóa mã di động sẽ phải bị quá tải nhiều lần (ghi nhật ký phát hiện rò rỉ bộ nhớ, triển khai bộ nhớ đặc biệt, v.v.) không nó? –

+0

@Als Trình biên dịch/cấu hình nền tảng sẽ đi vào hành vi không xác định cho các kiểu tích hợp sẵn (ví dụ int, char, v.v.) vì nó thực sự là một lỗi với nền tảng miễn phí() thực hiện, nhưng không có sửa lỗi cho nó nó là một nền tảng chết. – diverscuba23

Các vấn đề liên quan