2012-11-04 81 views
51

Bối cảnh: Tôi đang cố gắng quấn đầu quanh con trỏ, chúng tôi chỉ nhìn thấy chúng một vài tuần trước ở trường và trong khi thực hành hôm nay tôi chạy vào một ngớ ngẩn? vấn đề, nó có thể siêu đơn giản với bạn nhưng tôi có ít hoặc không có kinh nghiệm lập trình.Xóa con trỏ trong C++

Tôi đã thấy một vài câu hỏi trong SO về việc xóa con trỏ nhưng tất cả dường như liên quan đến việc xóa lớp và không phải là con trỏ 'đơn giản' (hoặc bất kỳ cụm từ thích hợp nào), đây là mã tôi đang cố gắng để chạy:

#include <iostream>; 

using namespace std; 

int main() { 
    int myVar, 
     *myPointer; 

    myVar = 8; 
    myPointer = &myVar; 

    cout << "delete-ing pointers " << endl; 
    cout << "Memory address: " << myPointer << endl; 

    // Seems I can't *just* delete it, as it triggers an error 
    delete myPointer; 
    cout << "myPointer: " << myPointer << endl; 
    // Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4: 
    // pointer being freed was not allocated 
    // *** set a breakpoint in malloc_error_break to debug 
    // Abort trap: 6 

    // Using the new keyword befor deleting it works, but 
    // does it really frees up the space? 
    myPointer = new int; 
    delete myPointer; 
    cout << "myPointer: " << myPointer << endl; 
    // myPointer continues to store a memory address. 

    // Using NULL before deleting it, seems to work. 
    myPointer = NULL; 
    delete myPointer; 
    cout << "myPointer: " << myPointer << endl; 
    // myPointer returns 0. 

} 

Vì vậy, câu hỏi của tôi là:

  1. Tại sao sẽ không phải là trường hợp đầu tiên làm việc? Dường như việc sử dụng đơn giản nhất để sử dụng và xóa một con trỏ là gì? Lỗi nói rằng bộ nhớ không được cấp phát nhưng 'cout' đã trả về một địa chỉ.
  2. Trên ví dụ thứ hai lỗi không được kích hoạt nhưng làm một cout giá trị của myPointer vẫn còn trả về địa chỉ bộ nhớ?
  3. # 3 thực sự có hoạt động không? Dường như làm việc với tôi, con trỏ không còn lưu trữ địa chỉ nữa, đây có phải là cách thích hợp để xóa con trỏ không?

Xin lỗi cho câu hỏi dài, muốn làm này càng rõ ràng càng tốt, cũng để nhắc lại, tôi có rất ít kinh nghiệm lập trình, vì vậy nếu ai đó có thể trả lời về sử dụng này của giáo dân, nó sẽ được đánh giá rất nhiều!

+11

Lý do bạn không thấy ví dụ đầu tiên là vì nó sai. Chỉ 'xóa' những gì bạn' mới'. Nó cũng không cần thiết cho con trỏ để thiết lập chính nó để NULL sau khi bạn xóa nó. Nếu bạn muốn an toàn ở đó, hãy sử dụng con trỏ thông minh để giải phóng bộ nhớ cho bạn và đưa ra lỗi khi bạn cố truy cập chúng khi chúng không giữ gì đó. – chris

+0

Hmm được rồi, tôi không chắc con trỏ thông minh là gì, nhưng tôi sẽ xem xét nó, cảm ơn! – leopic

+1

Tóm lại, họ làm những gì tôi mô tả. Để giữ một cái gì đó mới, bạn gọi là 'reset' và nó giải phóng cái cũ. Để giải phóng nó mà không cần thay thế, bạn gọi 'release'. Khi nó đi ra khỏi phạm vi, nó bị phá hủy, và có thể giải phóng bộ nhớ dựa trên loại đó là gì. 'std :: unique_ptr' chỉ dành cho một chủ sở hữu. 'std :: shared_ptr' giải phóng nó khi chủ sở hữu cuối cùng ngừng sở hữu tài nguyên. Họ cũng là ngoại lệ an toàn. Nếu bạn phân bổ một tài nguyên với một, và sau đó gặp phải một ngoại lệ, tài nguyên sẽ được giải phóng thích hợp. – chris

Trả lời

106

myVar = 8; //not dynamically allocated. Can't call delete on it. 
myPointer = new int; //dynamically allocated, can call delete on it. 

Biến đầu tiên được cấp phát trên stack. Bạn chỉ có thể gọi xóa trên bộ nhớ bạn đã phân bổ động (trên heap) bằng cách sử dụng toán tử new.

3.

myPointer = NULL; 
    delete myPointer; 

Trên đây đã gì cả. Bạn không giải phóng bất cứ thứ gì, vì con trỏ trỏ tới NULL.


Sau đây không nên được thực hiện:

myPointer = new int; 
myPointer = NULL; //leaked memory, no pointer to above int 
delete myPointer; //no point at all 

Bạn chĩa vào NULL, để lại đằng sau bộ nhớ bị rò rỉ (mới int bạn phân bổ). Bạn nên giải phóng bộ nhớ mình đang trỏ. Không có cách nào để truy cập được phân bổ new int nữa, do đó bị rò rỉ bộ nhớ.


Cách đúng:

myPointer = new int; 
delete myPointer; //freed memory 
myPointer = NULL; //pointed dangling ptr to NULL 

Cách tốt hơn:

Nếu bạn đang sử dụng C++, không sử dụng con trỏ thô.Sử dụng smart pointers thay vì có thể xử lý những thứ này cho bạn với chi phí thấp. C++ 11 đi kèm với several.

+9

"Trên ngăn xếp" là chi tiết triển khai - một trong đó C++ dễ thấy tránh đề cập đến. Cụm từ chính xác hơn là "với thời lượng lưu trữ tự động". (C++ 11, 3.7.3) cHao

+4

Cảm ơn bạn, tôi đã chọn câu trả lời của bạn cho a) giải thích những gì đã sai và b) đưa ra một phương pháp hay nhất, cảm ơn nhiều! – leopic

+0

Tôi muốn thêm, bất kể bài đăng này cũ bao nhiêu tuổi (vì lợi ích của googlers), 'xóa myPointer' deallocates' * myPointer' và 'myPointer' không còn trỏ vào bất kỳ thứ gì. Nó sẽ bị phá hủy ở cuối phạm vi. – Tqn

7

Có một quy tắc trong C++, cho mỗi mới có một xóa.

  1. Tại sao trường hợp đầu tiên không hoạt động? Dường như việc sử dụng đơn giản nhất để sử dụng và xóa một con trỏ là gì? Lỗi nói rằng bộ nhớ không được cấp phát nhưng 'cout' đã trả về một địa chỉ.

mới không bao giờ được gọi. Vì vậy, địa chỉ mà cout in là địa chỉ của vị trí bộ nhớ của myVar, hoặc giá trị được gán cho myPointer trong trường hợp này. Bằng cách viết:

myPointer = &myVar; 

bạn nói:

mypointer = Địa chỉ nơi dữ liệu trong myVar được lưu trữ

  1. On ví dụ thứ hai lỗi không được kích hoạt nhưng làm một cout giá trị của myPointer vẫn trả về một địa chỉ bộ nhớ?

Nó trả về địa chỉ trỏ đến vị trí bộ nhớ đã bị xóa. Bởi vì trước tiên bạn tạo con trỏ và gán giá trị của nó cho myPointer, thứ hai bạn xóa nó, thứ ba bạn in nó. Vì vậy, trừ khi bạn chỉ định một giá trị khác cho myPointer, địa chỉ đã xóa sẽ vẫn còn.

  1. # 3 có thực sự hoạt động không? Dường như làm việc với tôi, con trỏ không còn lưu trữ địa chỉ nữa, đây có phải là cách thích hợp để xóa con trỏ không?

NULL bằng 0, bạn xóa 0, vì vậy bạn không xóa gì cả. Và đó là logic mà nó in 0 vì bạn đã làm:

myPointer = NULL; 

đó bằng:

myPointer = 0; 
4
  1. Bạn đang cố gắng xóa một biến cấp phát trên stack. Bạn không thể thực hiện việc này
  2. Xóa con trỏ không hủy bỏ con trỏ thực sự, chỉ bộ nhớ bị chiếm đóng được trả lại cho hệ điều hành. Bạn có thể truy cập nó cho đến khi bộ nhớ được sử dụng cho một biến khác, hoặc nếu không được thao tác. Vì vậy, thực hành tốt là đặt con trỏ thành NULL (0) sau khi xóa.
  3. Xóa con trỏ NULL không xóa bất kỳ thứ gì.
10

Con trỏ tương tự như biến thông thường mà bạn không cần xóa chúng. Chúng được loại bỏ khỏi bộ nhớ ở phần cuối của một hàm thực thi và/hoặc kết thúc chương trình.

Bạn tuy nhiên có thể sử dụng con trỏ để phân bổ một 'khối' bộ nhớ, ví dụ như thế này:

int *some_integers = new int[20000] 

này sẽ phân bổ không gian bộ nhớ cho 20000 số nguyên. Hữu ích, vì Stack có kích thước giới hạn và bạn có thể muốn gây rối với tải trọng lớn 'ints' mà không có lỗi tràn ngăn xếp.

Bất cứ khi nào bạn gọi mới, bạn nên 'xóa' ở cuối chương trình, vì nếu không bạn sẽ bị rò rỉ bộ nhớ và một số không gian bộ nhớ được phân bổ sẽ không bao giờ được trả lại cho các chương trình khác để sử dụng. Để thực hiện việc này:

delete [] some_integers; 

Hy vọng điều đó sẽ hữu ích.

+1

Tôi muốn chỉ thêm rằng bộ nhớ được cấp phát S W được trả lại cho các chương trình khác để sử dụng, nhưng chỉ SAU KHI chương trình của bạn đã hoàn thành việc thực thi. – sk4l

1
int value, *ptr; 

value = 8; 
ptr = &value; 
// ptr points to value, which lives on a stack frame. 
// you are not responsible for managing its lifetime. 

ptr = new int; 
delete ptr; 
// yes this is the normal way to manage the lifetime of 
// dynamically allocated memory, you new'ed it, you delete it. 

ptr = nullptr; 
delete ptr; 
// this is illogical, essentially you are saying delete nothing. 
+1

Ngoài ra, hãy xem bài giảng này trên khung ngăn xếp http://www.youtube.com/watch?v=bjObm0hxIYY và http://www.youtube.com/watch?v=Rxvv9krECNw trên con trỏ. –

12

Tôi tin rằng bạn không hiểu rõ cách con trỏ hoạt động.
Khi bạn có một trỏ trỏ đến một số bộ nhớ có ba điều khác nhau mà bạn phải hiểu:
- có "cái gì là nhọn" của con trỏ (bộ nhớ)
- bộ nhớ này địa chỉ
- không phải tất cả con trỏ cần để xóa bộ nhớ của họ: bạn chỉ cần xóa bộ nhớ được phân bổ động (sử dụng toán tử new).

Hãy tưởng tượng:

int *ptr = new int; 
// ptr has the address of the memory. 
// at this point, the actual memory doesn't have anything. 
*ptr = 8; 
// you're assigning the integer 8 into that memory. 
delete ptr; 
// you are only deleting the memory. 
// at this point the pointer still has the same memory address (as you could 
// notice from your 2nd test) but what inside that memory is gone! 

Khi bạn đã làm

ptr = NULL; 
// you didn't delete the memory 
// you're only saying that this pointer is now pointing to "nowhere". 
// the memory that was pointed by this pointer is now lost. 

C++ cho phép quý vị cố gắng delete một con trỏ trỏ đến null nhưng nó không thực sự làm bất cứ điều gì, chỉ cần không cho bất kỳ lỗi nào.

+1

Cảm ơn, NÀY là siêu hữu ích, tôi nghĩ rằng tôi HAD để xóa tất cả các con trỏ, không biết đó là chỉ cho những người mới, cảm ơn. – leopic