Ein Destruktor - sollte ich löschen oder löschen []?

7

Ich schreibe eine Template-Klasse, die einen Zeiger als Eingabe nimmt und speichert. Der Zeiger soll auf ein Objekt zeigen, das von einer anderen Klasse zugewiesen wurde, und an die diese enthaltende Klasse übergeben werden.

Nun möchte ich einen Destruktor für diesen Container erstellen. Wie soll ich den Speicher freigeben, auf den dieser Zeiger zeigt? Ich weiß nicht a priori, ob es ein Array oder ein einzelnes Element ist.

Ich bin etwas neu in C ++, also ertragen Sie mit mir. Ich habe immer C verwendet, und Java ist meine OO-Sprache der Wahl, aber zwischen dem Wunsch, C ++ und den Geschwindigkeitsanforderungen meines Projekts zu lernen, bin ich mit C ++ gegangen.

Wäre es eine bessere Idee, den Container von einer Vorlage in einen Container für eine abstrakte Klasse zu ändern, die einen eigenen Destruktor implementieren kann?

    
Alex 03.02.2010, 20:39
quelle

11 Antworten

6

Wenn Sie nicht wissen, ob es mit new oder new[] zugeordnet wurde, ist es nicht sicher, es zu löschen.

Ihr Code scheint zu funktionieren. Auf einer Plattform, an der ich arbeite, spielt der Unterschied nur eine Rolle, wenn Sie ein Array von Objekten mit Destruktoren haben. Also tust du das:

%Vor%

aber dann machst du das:

%Vor%     
R Samuel Klatchko 03.02.2010, 20:44
quelle
6

Sie müssen dokumentieren, wie diese Klasse verwendet werden soll, und immer wie erwartet zuweisen. Sie können auch ein Flag an das Objekt übergeben, das angibt, wie es zerstört werden soll. Schauen Sie sich auch die Smartpointer von Boost an, die diese Unterscheidung für Sie übernehmen können.

    
Roger Pate 03.02.2010 20:45
quelle
5

Kurze Antwort:

Wenn Sie [] mit new verwenden, möchten Sie [] mit delete verwenden.

%Vor%

Das waren die nackten Knochen, die andere Sache, die Sie sich ansehen konnten, ist boost . Auch ziemlich schwierig zu beantworten, wenn man bedenkt, dass man nicht sicher ist, ob es ein Array oder ein einzelnes Objekt ist. Sie können dies jedoch über eine Markierung überprüfen, die Ihrer App mitteilt, ob Sie löschen oder löschen möchten [].

    
JonH 03.02.2010 20:42
quelle
2

Als allgemeine Entwicklungsregel sollten Sie bei einem Design bleiben, bei dem die Klasse, die new aufruft, auch delete

aufrufen soll     
alemjerus 03.02.2010 20:45
quelle
2

Sie sollten es überhaupt nicht löschen. Wenn Ihre Klasse einen bereits initialisierten Zeiger verwendet, ist es nicht sicher, sie zu löschen. Es könnte nicht einmal auf ein Objekt auf dem Heap zeigen; Der Aufruf von delete oder delete[] könnte katastrophal sein.

Die Zuweisung und Freigabe von Speicher sollte im selben Umfang erfolgen. Welcher Code auch immer die Instanz Ihrer Klasse besitzt und initialisiert, ist vermutlich auch verantwortlich für die Initialisierung und die Übergabe des Zeigers, und das ist der Ort, an dem Ihr delete sein sollte.

    
meagar 03.02.2010 20:46
quelle
2
  • Verwenden Sie delete , wenn Sie mit new .
  • zugewiesen wurden
  • Verwenden Sie delete[] , wenn Sie mit new[] .
  • zugewiesen wurden

Wenn Sie nach diesen Anweisungen weiterhin ein Problem haben (vielleicht möchten Sie ein Objekt löschen, das von jemand anderem erstellt wurde), brechen Sie die dritte Regel:

  • Löschen Sie immer, was Sie erstellt haben. Korollar, löschen Sie niemals, was Sie nicht erstellt haben.
Vincent Robert 03.02.2010 20:48
quelle
2

(Bewegt meinen Kommentar auf Anfrage in eine Antwort.)

JonHs Antwort ist richtig (über die Verwendung der Array-Zerstörung nur bei der Array-Konstruktion), also sollten Sie vielleicht Vorlagen anbieten: eine für Arrays, eine nicht.

Die andere Antwort besteht darin, Arrays zu vermeiden und stattdessen eine einzelne Instanz zu erwarten, die eine richtige Sammlung sein kann oder nicht, die nach sich selbst aufräumt, wie der Vektor & lt; & gt;.

Bearbeiten

Von Roger Pate stehlend, werde ich hinzufügen, dass Sie die Verwendung eines intelligenten Zeigers verlangen könnten, der zu einer Einzelpostensammlung führt.

    
Steven Sudit 03.02.2010 20:55
quelle
2

Wenn Sie eine Klasse haben, die einen Zeiger übernimmt, den sie übernehmen soll, dann muss der Vertrag für die Verwendung der Klasse ein paar Dinge enthalten. Entweder:

  • Die Schnittstelle muss angeben, wie das Objekt, auf das der Zeiger zeigt, zugewiesen wurde, damit der neue Besitzer wissen kann, wie das Objekt sicher freigegeben wird. Diese Option hat den Vorteil, die Dinge einfach zu halten (auf einer Ebene sowieso), aber sie ist nicht flexibel - die Klasse kann nicht damit umgehen, Besitz von statischen Objekten und dynamisch zugewiesenen Objekten zu übernehmen.

oder

  • Die Schnittstelle muss einen Mechanismus enthalten, in dem eine Freigabezuweisungsrichtlinie von dem angegeben werden kann, was den Zeiger auf die Klasse angibt. Dies kann so einfach sein wie das Bereitstellen eines Mechanismus zum Übergeben eines Funktors (oder sogar eines einfachen alten Funktionszeigers), der aufgerufen wird, um das Objekt freizugeben (vorzugsweise in derselben Funktion / demselben Konstruktor, der den Zeiger selbst durchläuft). Dies macht die Verwendung der Klasse möglicherweise komplizierter (aber eine Standardrichtlinie zum Aufrufen von delete für den Zeiger zum Beispiel macht es möglicherweise so einfach wie Option 1 für die meisten Anwendungen). Wenn nun jemand der Klasse einen Zeiger auf ein statisch zugewiesenes Objekt geben will, kann er einen no-op-Funktor übergeben, so dass nichts passiert, wenn die Klasse die Zuordnung aufheben will, oder ein Funktor zu einer delete[] -Operation, wenn das Objekt zugewiesen wurde von new[] , etc.
Michael Burr 03.02.2010 22:24
quelle
1

Da der Zeiger in C ++ uns nicht sagt, wie er zugewiesen wurde, gibt es keine Möglichkeit, zu entscheiden, welche Methode für die Zuweisung der Freigabe zu verwenden ist. Die Lösung besteht darin, dem Benutzer die Wahl zu geben, der hoffentlich weiß, wie der Speicher zugewiesen wurde. Sehen Sie sich die intelligente Smart-Bibliothek an, besonders bei shared_ptr -Konstruktor mit zweitem Parameter, für ein großartiges Beispiel.

    
Nikolai Fetissov 03.02.2010 20:47
quelle
0

Ein intelligenter Pointer wie Boost shared_pointer hat das bereits abgedeckt, könntest du es benutzen? linky

    
Alexander Torstling 03.02.2010 20:45
quelle
0

Einfach ausgedrückt: Wenn man nur einen Zeiger auf dynamisch zugewiesenen Speicher angibt, gibt es keine Möglichkeit, zu bestimmen, wie man ihn sicher zurückweist. Der Zeiger könnte auf eine der folgenden Arten zugewiesen worden sein:

  • mit neuen
  • unter Verwendung von new []
  • mit malloc
  • mit einer benutzerdefinierten Funktion
  • usw.

In allen Fällen, bevor Sie den Speicher freigeben können, müssen Sie wissen, wie er zugewiesen wurde.

    
anon 03.02.2010 21:02
quelle

Tags und Links