Để hiểu bộ nhớ giải phóng nghĩa là gì, trước tiên bạn phải hiểu những gì phân bổ phương tiện bộ nhớ. Sau đây là một lời giải thích đơn giản.
Có bộ nhớ. Bộ nhớ là một khối lượng lớn thứ bạn có thể truy cập. Nhưng vì nó toàn cầu, bạn cần một số cách để tách nó ra. Một số cách để chi phối ai có thể truy cập vào phần nào của bộ nhớ. Một trong những hệ thống điều chỉnh sự phân bổ bộ nhớ được gọi là "đống".
Vùng lưu trữ sở hữu một số lượng bộ nhớ (một số được sở hữu bởi ngăn xếp và một số được sở hữu bởi dữ liệu tĩnh, nhưng không bao giờ xảy ra bây giờ). Khi bắt đầu chương trình của bạn, heap nói rằng bạn có quyền truy cập vào bộ nhớ không thuộc sở hữu của heap.
Điều gì new int
thực hiện hai lần. Đầu tiên, nó đi vào hệ thống heap và nói, "Tôi muốn một bộ nhớ phù hợp để lưu trữ một int
vào." Nó lấy lại con trỏ chính xác: một phần của đống, để bạn có thể an toàn lưu trữ và truy xuất chính xác một giá trị thuộc loại int
.
Bây giờ bạn là chủ sở hữu tự hào về một giá trị bộ nhớ của int
. Heap đảm bảo miễn là các quy tắc của nó được tuân theo, bất kỳ điều gì bạn đặt ở đó sẽ được giữ nguyên cho đến khi bạn thay đổi nó một cách rõ ràng. Đây là giao ước giữa bạn và đống toàn năng.
Điều khác new int
là khởi tạo phần đó của đống với giá trị int
. Trong trường hợp này, nó được khởi tạo mặc định, bởi vì không có giá trị nào được thông qua (new int(5)
sẽ khởi tạo nó với giá trị 5).
Từ thời điểm này trở đi, bạn được phép lưu trữ chính xác một int
trong phần bộ nhớ này. Bạn được phép truy xuất int
được lưu trữ ở đó. Và bạn được phép làm một việc khác: nói với heap rằng bạn đã kết thúc bằng cách sử dụng bộ nhớ đó.
Khi bạn gọi delete p
, hai điều sẽ xảy ra. Đầu tiên, p
được khởi tạo. Một lần nữa, bởi vì nó là một int
, không có gì xảy ra. Nếu đây là một lớp, thì hàm hủy của nó sẽ được gọi.
Nhưng sau đó, delete
chuyển sang vùng heap và nói, "Hey heap: nhớ con trỏ này đến số int
bạn đã cho tôi? Tôi đã hoàn thành nó ngay bây giờ." Hệ thống heap có thể làm bất cứ điều gì nó muốn. Có lẽ nó sẽ xóa bộ nhớ, như một số heaps làm trong debug-builds. Tuy nhiên, trong bản phát hành, bộ nhớ có thể không bị xóa.
Tất nhiên, lý do tại sao vùng heap có thể làm bất cứ điều gì nó muốn là vì thời điểm bạn xóa con trỏ đó, bạn nhập vào thỏa thuận mới với heap. Trước đây, bạn đã yêu cầu một bộ nhớ cho một số int
và số tiền có nghĩa vụ. Bạn sở hữu trí nhớ đó, và heap đảm bảo rằng nó là của bạn miễn là bạn muốn. Thứ bạn đặt ở đó sẽ vẫn còn đó.
Sau khi bạn có niềm vui, bạn đã trả lại nó cho nhóm. . Và đây là nơi mà các hợp đồng do thỏa thuận hợp Khi bạn nói delete p
, cho bất kỳ đối tượng p
, bạn đang nói những điều sau đây:
Tôi long trọng thề không để chạm vào địa chỉ bộ nhớ này một lần nữa!
Bây giờ, heap có thể cung cấp địa chỉ bộ nhớ đó cho bạn nếu bạn gọi lại new int
. Nó có thể cung cấp cho bạn một cái khác. Nhưng bạn chỉ có quyền truy cập vào bộ nhớ được phân bổ theo heap trong thời gian giữanew
và delete
.
Với điều này, điều này có nghĩa là gì?
delete p;
cout << *p << "\t" << p << "\n";
Trong ngôn ngữ C++, điều này được gọi là "hành vi không xác định". Đặc điểm kỹ thuật C++ có rất nhiều thứ được cho là "không xác định". Khi bạn kích hoạt hành vi không xác định , mọi thứ đều có thể xảy ra!*p
có thể là 0 *p
có thể là giá trị được sử dụng. Làm *p
có thể làm hỏng chương trình của bạn.
Đặc tả C++ là hợp đồng giữa bạn và trình biên dịch/máy tính của bạn. Nó nói những gì bạn có thể làm, và nó nói như thế nào hệ thống đáp ứng. "Hành vi không xác định" là điều xảy ra khi bạn ngắt hợp đồng, khi bạn làm điều gì đó, đặc điểm kỹ thuật của C++ cho biết bạn không được phép. Tại thời điểm đó, bất cứ điều gì có thể xảy ra.
Khi bạn gọi số delete p
, bạn đã nói với hệ thống rằng bạn đã hoàn thành bằng cách sử dụng p
. Bằng cách sử dụng lại, bạn đã nằm vào hệ thống. Và do đó, hệ thống không còn phải tuân theo bất kỳ quy tắc nào, như lưu trữ các giá trị bạn muốn lưu trữ. Hoặc tiếp tục chạy. Hoặc không sinh ra ma quỷ từ mũi của bạn. Hay bất cứ cái gì.
Bạn đã phá vỡ các quy tắc. Và bạn phải chịu hậu quả.
Vì vậy, không, delete p
không tương đương với *p = 0
. Cái sau chỉ đơn giản có nghĩa là "đặt 0 vào bộ nhớ được trỏ đến bởi p
." Điều này có nghĩa là "Tôi đã hoàn thành việc sử dụng bộ nhớ được chỉ định bởi p
, và tôi sẽ không sử dụng lại nó cho đến khi bạn nói với tôi rằng tôi có thể."
Vâng, ít nhất nó cũng xóa dữ liệu được trỏ đến bởi con trỏ, nhưng tôi chắc rằng một người nào đó sẽ có câu trả lời tốt hơn nhiều về những gì "xóa" bộ nhớ thực sự có nghĩa là. Tôi nghi ngờ nó thậm chí có thể không phải là bộ nhớ, nhưng thay vì chỉ cho phép không gian đó được phân bổ một lần nữa. – prelic
Sử dụng một chút suy nghĩ phê phán - làm thế nào '* p = 0' thậm chí hoạt động cho ví dụ: 'std :: string'? – ildjarn