2010-05-26 12 views
32

Was ist der Unterschied zwischen Löschen eines Zeigers, setzen Sie es auf Null, und es zu befreien.löschen vs NULL vs frei in C++

delete ptr; 

vs.

ptr=NULL; 

vs.

free(ptr); 
+1

C hat kein Konzept von 'löschen'. Meinst du nur C++? – GManNickG

+3

Ihre Frage schlägt vor, dass Sie aus einer Sprache mit * Garbage Collection * wie Java oder C# kommen. C++ hat das nicht. Siehe meine Antwort für weitere Details. –

+0

@GMan, C hat frei, was in diesem Zusammenhang im Wesentlichen das Gleiche ist. –

Antwort

43

Ihre Frage schlägt vor, dass Sie aus einer Sprache stammen, die Garbage Collection enthält. C++ hat keine Speicherbereinigung.

Wenn Sie einen Zeiger auf NULL setzen, führt dies nicht dazu, dass der Speicher zum Pool des verfügbaren Speichers zurückkehrt. Wenn keine anderen Zeiger auf diesen Speicherblock zeigen, haben Sie jetzt einfach einen "verwaisten" Speicherblock, der reserviert bleibt, aber jetzt nicht erreichbar ist - ein Leck. Lecks führen nur zum Absturz eines Programms, wenn sie bis zu einem Punkt aufgebaut sind, an dem kein Speicher mehr zugewiesen werden kann.

Es gibt auch die umgekehrte Situation, wo Sie delete einen Speicherblock mit einem Zeiger, und später versuchen, auf diesen Speicher zuzugreifen, als ob es noch zugeordnet war. Dies ist möglich, weil der Aufruf von delete für einen Zeiger den Zeiger nicht auf NULL setzt - er zeigt immer noch auf die Adresse des zuvor zugewiesenen Speichers. Ein Zeiger auf Speicher, der nicht mehr zugeordnet ist, wird als dangling Zeiger bezeichnet und der Zugriff darauf führt normalerweise zu merkwürdigem Programmverhalten und Abstürzen, da sein Inhalt wahrscheinlich nicht das ist, was Sie erwarten - dieser Speicherabschnitt wurde seither für einige neu zugeordnet anderer Zweck.

[EDIT] Wie stinky472 erwähnt, ein weiterer Unterschied zwischen delete und free() ist, dass nur der ehemalige Destruktor des Objekts Anruf.(Denken Sie daran, dass Sie delete für ein Objekt mit new und free() für Speicher mit malloc() zugewiesen werden müssen - sie können nicht gemischt werden.) In C++ ist es immer am besten statische Zuordnung zu verwenden, wenn nicht, dann lieber new bis malloc().

+2

FTR, diese Antwort war als Reaktion auf rev 1 der Frage: "Was ist der Unterschied zwischen dem Löschen eines Zeigers und dem Setzen auf NULL?" –

+1

+1 Es ist auch wert, in dieser neuen Revision darauf hinzuweisen, dass free keine Destruktoren für UDTs aufruft und generell in C++ vermieden werden sollte (es sei denn, ein Speicherzuordner wird implementiert). – stinky472

+0

Auch die Verwendung von malloc/free/realloc/calloc und dergleichen bei Nicht-POD-Typen in C++ führt zu undefiniertem Verhalten. –

26

delete geben Speicher zurück in die C++ Laufzeitbibliothek zugeordnet. Sie benötigen immer einen passenden new, der den Speicher auf dem Heap zuvor zugewiesen hat. NULL ist etwas ganz anderes. Ein "Platzhalter" bedeutet, dass er auf keine Adresse zeigt. In C++ ist NULL ein MACRO definiert als 0. Also wenn MACROS nicht mögen, ist es auch möglich 0 direkt zu verwenden. In C++ wird 0x nullptr eingeführt und bevorzugt.

Beispiel:

int* a;  //declare pointer 
a = NULL;  //point 'a' to NULL to show that pointer is not yet initialized 
a = new int; //reserve memory on the heap for int 

//... do more stuff with 'a' and the memory it points to 

delete a;  //release memory 
a = NULL;  //(depending on your program), you now want to set the pointer back to 
       // 'NULL' to show, that a is not pointing to anything anymore 
+1

technisch geben Sie es an die C Runtime-Bibliothek zurück, die es dann möglicherweise an das OS zurückgeben kann oder nicht. – shoosh

+3

Tatsächlich geben Sie es an die C++ Runtime-Bibliothek zurück, die es möglicherweise an die C-Laufzeitbibliothek oder das Betriebssystem zurückgibt. – MSalters

+0

@MSalters: Bearbeitet, wieder :) – Lucas

5

gut, wenn Sie Objekt dynamisch erstellt (mit ‚neuen‘), Zeiger auf einen beliebigen Wert einstellen nicht gelöscht Objekt aus dem Speicher - und Sie erhalten einen Speicherverlust.

2

Wenn Sie ein Objekt mit new erstellen, müssen Sie mit delete den Speicher zurück zum System freigeben. Der Speicher steht dann anderen zur Wiederverwendung zur Verfügung.


int* a = new int; 
delete a; 

NULL ist nur eine vordefinierte Makro, das einen Zeiger zugewiesen werden kann bedeuten, dass es nicht zu irgendetwas nicht zeigen.


int* a = new int; 
a = NULL; 

Im obigen Fall weisen Sie nach dem Zuweisen von Speicher für a NULL zu. Der zuvor für a zugewiesene Speicher wurde jedoch nicht freigegeben und kann vom System nicht erneut verwendet werden. Dies nennen wir Speicherleck.

4

Wie bei jeder indirection gibt es zwei Objekte beteiligt, wenn Zeiger verwendet werden: der Referrer (den Zeiger, in Ihrem Beispiel ptr) und das referenzierte Objekt (was er zeigt, *ptr). Sie müssen lernen, zwischen ihnen zu unterscheiden.

Wenn Sie NULL einen Zeiger zuweisen, nur der Zeiger betroffen ist ist es die Aufgabe bezieht sich auf sich allein gelassen. Wenn der Zeiger der letzte war, der auf dieses Objekt zeigt, haben Sie den letzten Verweiszeiger verloren, der darauf zeigt und daher nicht mehr verwendet werden kann. In C++ jedoch das bedeutet nicht, dass das Objekt gelöscht wird. C++ hat keine Garbage Collection. So ist das Objekt durchgesickert.

Um Objekte gelöscht werden, können Sie sie manuell löschen indem ihre Adresse haben wird (in einem Zeiger gespeichert) an den delete Operator. Wenn Sie dies tun, nur das Objekt wird betroffen sein, der Zeiger ist in Ruhe gelassen. Es könnte immer noch auf die Adresse zeigen, wo sich das Objekt im Speicher befand, obwohl das nicht mehr verwendbar ist. Das nennt man dangling pointer.

+0

was ist mit free (ptr) – hero

+0

Der Zeiger ist nicht unbedingt ein Objekt, zum Beispiel in 'delete new int' oder' delete function() 'oder' delete ptr - 1'. – fredoverflow

+1

@hero: Sie löschen Objekte, die Sie mit 'new' erhalten haben, Sie löschen []' Arrays, die Sie mit 'new []' erhalten, Sie 'free()' Speicher erhalten mit 'malloc()' usw. In C++ sollten Sie 'malloc()' nicht verwenden. Es wird dynamisch __memory__ zugewiesen, während 'new' dynamisch zugeordnete __Objekte__ erstellt. Was "neu" ist, ist im Prinzip [Speicher zuweisen __ und das Objekt__ durch Aufruf des Konstruktors des Typs zu erzeugen] (http://stackoverflow.com/questions/1820069/1820092#1820092). – sbi

1
int * ptr = null; 

Aufruf free(ptr) wird nichts tun. Wenn der angegebene Zeiger null ist, passiert standardmäßig keine Aktion.

Mit delete p wird auch nichts tun. Der C++ - Standard sagt, dass keine Aktion stattfinden wird, weil sie auf nichts zeigt und kein Typ verfügbar ist.