webentwicklung-frage-antwort-db.com.de

Einen Zeiger in C ++ löschen

Ausgangssituation: Ich versuche, Zeiger in den Kopf zu stecken. Wir haben sie vor ein paar Wochen in der Schule gesehen, und als ich heute übte, bin ich auf einen albernen Menschen gestoßen? Problem, es kann super einfach für Sie sein, aber ich habe wenig bis gar keine Programmiererfahrung.

Ich habe in SO über das Löschen von Zeigern schon einige Fragen gesehen, aber sie scheinen alle mit dem Löschen einer Klasse und nicht mit einem "einfachen" Zeiger (oder was auch immer der richtige Begriff sein mag) zu tun zu haben. Hier ist der Code, den ich ausführen möchte:

#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.

}

Meine Fragen sind also:

  1. Warum funktioniert der erste Fall nicht? Scheint die einfachste Verwendung, um einen Zeiger zu verwenden und zu löschen? Der Fehler besagt, dass der Speicher nicht zugewiesen wurde, 'cout' aber eine Adresse zurückgegeben hat.
  2. Im zweiten Beispiel wird der Fehler nicht ausgelöst, sondern es wird ein Cout des Wertes von myPointer durchgeführt noch gibt eine Speicheradresse zurück?
  3. Funktioniert # 3 wirklich? Scheint für mich zu funktionieren, der Zeiger speichert keine Adresse mehr. Ist dies der richtige Weg, um einen Zeiger zu löschen?

Entschuldigung für die lange Frage, wollte dies so klar wie möglich machen, auch wiederholen, ich habe wenig Programmiererfahrung, also wenn jemand dies unter Verwendung von Laienbegriffen beantworten könnte, wäre es sehr dankbar!

76
leopic

1 & 2

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

Die erste Variable wurde auf dem Stapel zugeordnet. Mit dem Operator new können Sie delete nur für den Speicher aufrufen, den Sie dynamisch (auf dem Heap) zugewiesen haben.

3.

  myPointer = NULL;
  delete myPointer;

Das obige tat überhaupt nichts . Sie haben nichts befreit, da der Zeiger auf NULL zeigte.


Folgendes sollte nicht getan werden:

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

Sie haben auf NULL verwiesen und dabei den durchgesickerten Speicher (den von Ihnen zugewiesenen neuen Int) zurückgelassen. Sie sollten den Speicher freigeben, auf den Sie zeigten. Es gibt keine Möglichkeit, auf das zugewiesene new int mehr, daher Speicherverlust.


Der richtige Weg:

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

Der bessere Weg:

Wenn Sie C++ verwenden, verwenden Sie keine rohen Zeiger . Verwenden Sie stattdessen intelligente Zeiger , die diese Dinge mit geringem Aufwand für Sie erledigen können. C++ 11 enthält mehrere .

147

Ich glaube, Sie verstehen nicht ganz, wie Zeiger funktionieren.
Wenn Sie einen Zeiger haben, der auf etwas Gedächtnis zeigt, müssen Sie drei verschiedene Dinge verstehen:
- da ist "was wird gezeigt" durch den Zeiger (die Erinnerung)
- diese Speicheradresse
- Nicht bei allen Zeigern muss der Speicher gelöscht werden: Sie müssen nur den Speicher löschen, der dynamisch zugewiesen wurde (benutzter new -Operator).

Vorstellen:

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!

Als du es getan hast

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.

Mit C++ können Sie versuchen, einen Zeiger auf delete zu setzen, der auf null zeigt, aber tatsächlich nichts tut, sondern nur keinen Fehler ausgibt.

18
salgadokk

Zeiger ähneln normalen Variablen, da Sie sie nicht löschen müssen. Sie werden am Ende einer Funktionsausführung und/oder am Ende des Programms aus dem Speicher entfernt.

Sie können jedoch Zeiger verwenden, um einen 'Speicherblock' zuzuweisen. Beispiel:

int *some_integers = new int[20000]

Dadurch wird Speicherplatz für 20000 Ganzzahlen zugewiesen. Dies ist nützlich, da der Stapel eine begrenzte Größe hat und Sie möglicherweise mit einer großen Menge an Ints herumspielen möchten, ohne dass ein Stapelüberlauffehler auftritt.

Wenn Sie neu aufrufen, sollten Sie am Ende Ihres Programms "löschen", da sonst ein Speicherverlust auftritt und ein Teil des zugewiesenen Speicherplatzes niemals für andere Programme zurückgegeben wird. Um dies zu tun:

delete [] some_integers;

Ich hoffe, das hilft.

11
user3728501

In C++ gibt es eine Regel, für jedes ne gibt es ein löschen.

  1. Warum funktioniert der erste Fall nicht? Scheint die einfachste Verwendung zu sein, um einen Zeiger zu verwenden und zu löschen? Der Fehler besagt, dass der Speicher nicht zugewiesen wurde, aber 'cout' eine Adresse zurückgegeben hat.

neu heißt nie. Die Adresse, die cout ausgibt, ist also die Adresse des Speicherorts von myVar oder der Wert, der in diesem Fall myPointer zugewiesen wurde. Durch das Schreiben:

myPointer = &myVar;

du sagst:

myPointer = Die Adresse, an der die Daten in myVar gespeichert sind

  1. Im zweiten Beispiel wird der Fehler nicht ausgelöst, aber wenn Sie einen Cout des Werts von myPointer ausführen, wird trotzdem eine Speicheradresse zurückgegeben?

Es gibt eine Adresse zurück, die auf einen Speicherort verweist, der gelöscht wurde. Denn erstens erstellen Sie den Zeiger und weisen ihn myPointer zu, zweitens löschen Sie ihn und drittens drucken Sie ihn aus. Wenn Sie myPointer also keinen anderen Wert zuweisen, bleibt die gelöschte Adresse erhalten.

  1. Funktioniert # 3 wirklich? Scheint für mich zu funktionieren, der Zeiger speichert keine Adresse mehr. Ist dies der richtige Weg, um einen Zeiger zu löschen?

NULL ist gleich 0, Sie löschen 0, Sie löschen also nichts. Und es ist logisch, dass es 0 ausgibt, weil Sie es getan haben:

myPointer = NULL;

was gleich ist:

myPointer = 0;
7
fonZ
  1. Sie versuchen, eine auf dem Stapel zugewiesene Variable zu löschen. Du kannst das nicht machen
  2. Das Löschen eines Zeigers zerstört einen Zeiger nicht wirklich, nur der belegte Speicher wird an das Betriebssystem zurückgegeben. Sie können darauf zugreifen, bis der Speicher für eine andere Variable verwendet oder anderweitig manipuliert wird. Daher ist es ratsam, nach dem Löschen einen Zeiger auf NULL (0) zu setzen.
  3. Das Löschen eines NULL-Zeigers löscht nichts.
4
Hakan Serce
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
Casper Beyer