Scott Meyers nói trong cuốn sách C++ hiệu quả của mình: Mục 5: Sử dụng cùng một biểu mẫu trong cách sử dụng tương ứng của mới và xóa.
Câu hỏi lớn về xóa là: có bao nhiêu đối tượng nằm trong bộ nhớ bị xóa? Câu trả lời cho rằng xác định có bao nhiêu destructors phải được gọi.
Con trỏ có bị xóa điểm tới một đối tượng đơn lẻ hay một mảng đối tượng không? Cách duy nhất để xóa để biết là để bạn nói với nó. Nếu bạn không sử dụng dấu ngoặc trong việc sử dụng của bạn xóa, xóa giả định một đối tượng duy nhất được trỏ đến.
Ngoài ra, các cấp phát bộ nhớ có thể phân bổ nhiều không gian cần thiết để lưu trữ đối tượng của bạn và trong trường hợp này chia kích thước của khối nhớ được trả về bởi kích thước của mỗi đối tượng sẽ không hoạt động.
Tùy thuộc vào nền tảng, các chức năng _msize
(windows), malloc_usable_size
(linux) hoặc malloc_size
(osx) sẽ cho bạn biết độ dài thực của khối được phân bổ. Thông tin này có thể được khai thác khi thiết kế các thùng chứa đang phát triển.
Một lý do khác khiến nó không hoạt động là Foo* foo = new Foo[10]
gọi operator new[]
để cấp phát bộ nhớ. Sau đó, delete [] foo;
gọi operator delete[]
để deallocate bộ nhớ. Vì các toán tử đó có thể bị quá tải, bạn phải tuân theo quy ước delete foo;
gọi operator delete
có thể có triển khai không tương thích với operator delete []
. Đó là vấn đề ngữ nghĩa, không chỉ theo dõi số lượng đối tượng được cấp phát để phát hành đúng số lượng cuộc gọi hủy.
Xem thêm:
[16.14] After p = new Fred[n], how does the compiler know there are n objects to be destructed during delete[] p?
Câu trả lời ngắn: Magic.
Câu trả lời dài: Hệ thống thời gian chạy lưu trữ số lượng đối tượng, n, nơi nào đó có thể truy xuất được nếu bạn chỉ biết con trỏ, p. Có hai kỹ thuật phổ biến làm điều này. Cả hai kỹ thuật này đang được sử dụng bởi các trình biên dịch cấp thương mại, cả hai đều có sự cân bằng, và cả hai đều không hoàn hảo.Những kỹ thuật này là:
EDIT: sau khi có ý kiến @AndreyT đọc, tôi đào vào bản sao của tôi của Stroustrup "Thiết kế và Sự phát triển của C++" và trích như sau:
Làm thế nào để chúng tôi đảm bảo rằng một mảng được xóa một cách chính xác? Đặc biệt, làm thế nào để đảm bảo rằng destructor được gọi cho tất cả các phần tử của một mảng?
...
Xóa đồng bộ là không bắt buộc để xử lý cả hai đối tượng riêng lẻ một mảng. Điều này tránh làm phức tạp các trường hợp phổ biến của phân bổ và deallocating các đối tượng cá nhân. Nó cũng tránh encumbering các đối tượng cá nhân với các thông tin cần thiết cho mảng deallocation.
Phiên bản trung gian của lệnh xóa [] yêu cầu người lập trình chỉ định số phần tử của mảng.
...
Điều đó tỏ ra quá dễ bị lỗi, do đó, gánh nặng theo dõi số lượng phần tử được đặt vào thực hiện thay thế.
Như @Marcus đã đề cập, lý trí có thể là "bạn không trả tiền cho những gì bạn không sử dụng".
EDIT2:
Trong "The C++ Ngôn ngữ lập trình, 3rd edition", §10.4.7, Bjarne Stroustrup viết:
Chính xác như thế nào mảng và các đối tượng cá nhân được Nhà nước giao là implementation- phụ thuộc. Do đó, các triển khai khác nhau sẽ phản ứng khác nhau đối với việc sử dụng không chính xác của các toán tử xóa và xóa []. Trong các trường hợp đơn giản và không quan tâm như trường hợp trước, trình biên dịch có thể phát hiện vấn đề, nhưng nói chung điều gì đó khó chịu sẽ xảy ra vào thời gian chạy.
Toán tử hủy diệt đặc biệt cho mảng, xóa [], không cần thiết về mặt logic. Tuy nhiên, giả sử việc thực hiện kho lưu trữ miễn phí đã được yêu cầu phải chứa đủ thông tin cho mọi đối tượng để cho biết đó là một cá nhân hay một mảng. Người dùng có thể đã được giảm bớt gánh nặng, nhưng nghĩa vụ đó sẽ áp đặt các chi phí đáng kể về thời gian và không gian trên một số triển khai C++.
+1 cho sách của Scott Meyers: các lập trình viên _all_ C++ nên sở hữu và đọc sách C++ hiệu quả và hiệu quả hơn. – AAT
Lời giải thích * của Scott không thực sự là một lời giải thích chút nào. Nó chỉ là một sự khẳng định của sự thật, được giải thích một cách khôn ngoan như một "lời giải thích". Ông nói rằng cách duy nhất để biết liệu nó là một mảng hay một đối tượng duy nhất là hỏi người dùng. Đây là, tất nhiên, không chính xác. Hoàn toàn có thể lưu trữ thông tin đó trong 'new []' và sau đó lấy lại trong 'delete', giống như nó được thực hiện ngay bây giờ với số phần tử. Quyết định đã được đưa ra chống lại nó, bởi vì nó sẽ quá phức tạp "hộ gia đình" thông tin cấu trúc và phân nhánh trong 'xóa'. Không có lời giải thích "xinh đẹp", nó đơn giản là * quyết định * theo cách đó. – AnT
@ Jason: Không, lời giải thích của Scott hoàn toàn không có thật. Một lần nữa, làm thế nào để bạn biết có bao nhiêu phần tử trong mảng khi bạn thực hiện 'delete []'? Huh? Bạn có phải nói với nó để 'xóa []' chính mình? Số 'xóa []' "biết" nó bởi vì nó sử dụng thông tin hộ gia đình được chuẩn bị bởi 'new []'. Trong chính xác giống như cách chúng ta có thể bắt buộc 'new' \' new [] 'lưu trữ thông tin gia đình bổ sung về bản chất" mảng hay không ". Nó rất dễ dàng và rõ ràng. Đó là câu trả lời cho câu hỏi của bạn. – AnT