2012-01-31 35 views
5
# include <iostream> 

int main() 
{ 
using std::cout; 
int *p= new int; 

*p = 10; 
cout<<*p<<"\t"<<p<<"\n"; 
delete p; 
cout<<*p<<"\t"<<p<<"\n"; 

return 0; 

} 

Output:
10 0x237c010
0 0x237c010'Xóa con trỏ' có nghĩa là '* pointer = 0' không?

đây sau khi xóa p, tại sao con trỏ p giữ lại giá trị của nó? Không xóa giải phóng con trỏ p?
Chính xác là gì khi 'giải phóng con trỏ'?
Liệu 'xóa p' chỉ đơn giản có nghĩa là '* p = 0'? (Mà dường như từ đầu ra)

+0

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

+2

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

Trả lời

6

đây sau khi xóa p, tại sao con trỏ p giữ lại giá trị của nó?

Đó là cách ngôn ngữ được thiết kế. Nếu bạn muốn con trỏ bạn giữ là zeroed, bạn sẽ cần phải gán nó bằng không cho mình. Con trỏ p là một phần khác của bộ nhớ, tách biệt với phân bổ/đối tượng mà nó trỏ tới.

Không xóa giải phóng con trỏ p?

Nó gọi trình phá hủy đối tượng và trả bộ nhớ cho hệ thống (như miễn phí). Nếu nó là một mảng (delete[]), các bộ hủy cho tất cả các phần tử sẽ được gọi, sau đó bộ nhớ sẽ được trả về.

Chính xác có nghĩa là gì khi 'giải phóng con trỏ'?

Khi bạn muốn một phần bộ nhớ từ hệ thống, bạn phân bổ bộ nhớ đó (ví dụ: sử dụng new). Khi bạn sử dụng xong, bạn trả lại bằng cách sử dụng cuộc gọi miễn phí/xóa tương ứng. Đó là một tài nguyên mà bạn phải quay trở lại. Nếu bạn không, chương trình của bạn sẽ bị rò rỉ (và không ai muốn điều đó).

+0

@ Justin- Bạn vui lòng giải thích lý do tại sao con trỏ p đã giữ lại giá trị của nó trong mã trên ngay cả sau khi xóa? –

+3

@Avinash: Tại sao nên deallocating bộ nhớ thay đổi nội dung của nó? – ildjarn

+0

@AvinashSonawane mở rộng – justin

0

delete p đơn giản giải phóng bộ nhớ được phân bổ trong khi gọi đến toán tử new. Nó không thay đổi giá trị của con trỏ hoặc nội dung của bộ nhớ deallocated.

+0

'delete' đảm bảo rằng destructor được gọi, có thể thay đổi giá trị của con trỏ hoặc nội dung của bộ nhớ deallocated. –

+0

@ Narrakan- Nếu không có thay đổi về giá trị con trỏ cũng như giá trị nhọn thì chính xác những gì đạt được bằng cách giải phóng bộ nhớ? Vì giá trị con trỏ không bị thay đổi nên ai cũng có thể truy cập đối tượng 'đã xóa' đó. –

+0

@AvinashSonawane tốt, như bạn đã thấy một mình, bạn có thể truy cập '* p' ngay cả sau khi bạn' xóa'd nó, vì vậy bạn vẫn có thể truy cập bộ nhớ đó, mặc dù nó là hành vi không xác định. –

1

Ở đây sau khi xóa p, tại sao con trỏ p giữ lại giá trị của nó? Không xóa giải phóng con trỏ p?

Nó giải phóng bộ nhớ con trỏ trỏ tới (sau khi gọi bất kỳ trình phá hủy thích hợp nào). Giá trị của con trỏ chính nó là không thay đổi.

Chính xác có nghĩa là gì khi 'giải phóng con trỏ'?

Như trên - điều đó có nghĩa là giải phóng bộ nhớ mà con trỏ trỏ đến.

Liệu 'xóa p' chỉ đơn giản có nghĩa là '* p = 0'? (Mà dường như từ đầu ra)

số Hệ thống không để viết bất cứ điều gì vào bộ nhớ đó là giải phóng, và nếu nó viết một cái gì đó nó không phải viết 0. Tuy nhiên, hệ thống thường phải quản lý bộ nhớ đó theo một cách nào đó, và điều đó thực sự có thể ghi vào vùng bộ nhớ mà con trỏ trỏ đến.Ngoài ra, bộ nhớ chỉ giải phóng có thể được cấp phát cho một thứ khác (và trong một ứng dụng đa luồng, điều đó có thể xảy ra trước khi hoạt động delete thậm chí còn trả về). Chủ sở hữu mới của khối bộ nhớ đó có thể viết tất cả những gì họ muốn vào bộ nhớ đó.

Con trỏ trỏ đến khối bộ nhớ được giải phóng thường được gọi là con trỏ 'đang lơ lửng'. Đó là một lỗi để dereference một con trỏ lơ lửng (để đọc hoặc viết). Đôi khi bạn sẽ thấy mã ngay lập tức gán NULL hoặc 0 cho con trỏ ngay sau khi xóa con trỏ, đôi khi sử dụng macro hoặc mẫu hàm mà cả hai đều xóa và xóa con trỏ. Lưu ý rằng điều này sẽ không khắc phục tất cả các lỗi có con trỏ lơ lửng, vì các con trỏ khác có thể đã được thiết lập để trỏ đến khối bộ nhớ.

Phương pháp xử lý các vấn đề hiện đại này là tránh sử dụng con trỏ thô hoàn toàn có lợi cho việc sử dụng con trỏ thông minh như shared_ptr hoặc unique_ptr.

0

(Lưu ý những điều sau đây không phải là cách nó thực sự hoạt động rất mang nó theo một hạt muối.)

Bên trong việc thực hiện mới nó giữ một danh sách của tất cả các bộ nhớ có sẵn khi bạn nói "int * p = int mới; " nó cắt một khối có kích thước int ra khỏi danh sách bộ nhớ sẵn có của nó và đưa nó cho bạn. Khi bạn chạy "xóa p;" nó được đưa trở lại vào danh sách bộ nhớ có sẵn. Nếu chương trình của bạn được gọi là 30 lần mới mà không cần gọi xóa, bạn sẽ nhận được 30 đoạn mã có kích thước khác nhau từ mới. Nếu bạn gọi mới, sau đó xóa 30 lần liên tiếp, bạn có thể (nhưng không nhất thiết) nhận được cùng một khối có kích thước. Điều này là do bạn nói rằng bạn không sử dụng nó nữa khi bạn gọi là xóa và vì vậy mới được tự do sử dụng lại nó.

TLDR; Xóa thông báo mới rằng phần này của bộ nhớ có sẵn một lần nữa nó không chạm vào biến của bạn.

2

Để 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ữanewdelete.

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 *pcó 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ể."

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