Frage

Ich habe einige Code bekam, die eine Menge von Zeigern verwendet, um die gleiche Adresse zeigen. Gegeben Beispiel ein Äquivalent einfach:

int *p =  new int(1);
int *q = p;
int *r = q;

delete r; r = NULL; // ok
// delete q; q = NULL; // NOT ok
// delete p; p = NULL; // NOT ok

Wie man es sicher ohne mehrere Lösch löschen? Dies ist besonders schwierig, wenn ich eine Menge von Objekten, die Zeiger alle auf der gleichen Adresse.

War es hilfreich?

Lösung

Die Antwort, ohne auf verwaltete Zeiger zurückgreifen, ist, dass Sie sollten wissen, ob ein Zeiger zu löschen, basierend auf, wo er zugeordnet wurde.

Ihr Beispiel ist eine Art erfunden, aber in einer realen Welt Anwendung, das Objekt verantwortlich für das Zuweisen von Speicher für verantwortlich wäre es zu zerstören. Methoden und Funktionen, die bereits initialisiert Zeiger empfangen und speichern sie eine Zeit lang nicht diese Zeiger löschen; dass die Verantwortung liegt mit dem, was Objekt ursprünglich den Speicher zugewiesen.

Denken Sie daran, dass Sie Ihre Anrufe zu new sollten durch Ihre Anrufe zu delete ausgeglichen werden. Jedesmal, wenn Sie Speicher zuweisen, Sie wissen Sie balancieren Code schreiben (oft ein destructor), dass der Speicher freizugeben.

Andere Tipps

Ihr Werkzeug der shared_ptr Bibliothek boost. Werfen Sie einen Blick in die Dokumentation: http: //www.boost. org / doc / libs / 1_44_0 / libs / smart_ptr / shared_ptr.htm

Beispiel:

void func() {
  boost::shared_ptr<int> p(new int(10));
  boost::shared_ptr<int> q(p);
  boost::shared_ptr<int> r(q);

  // will be destructed correctly when they go out of scope.
}

Die „moderne“ Antwort ist ein Smart-Pointer zu verwenden und machen keine manuellen Löschungen.

boost::shared_ptr<int> p(new int(1));
boost::shared_ptr<int> q = p;
boost::shared_ptr<int> r = q;

Ende der Geschichte!

Die Problem Sie konfrontiert sind, ist, dass das Eigentum Semantik in Ihrem Programm ist nicht klar. Aus gestalterischen Sicht versuchen, festzustellen, wer der Eigentümer der Objekte bei jedem Schritt. In vielen Fällen, die implizieren, dass, wer das Objekt, um es später müssen gelöscht werden erstellt, aber in anderen Fällen kann das Eigentum oder sogar geteilt übertragen werden.

Wenn Sie wissen, wer den Speicher besitzt, dann Code zurückgehen und es umzusetzen. Wenn ein Objekt die alleinige Verantwortung für ein anderes Objekt ist, sollten die sie halten es durch einen einzigen Besitz Smart-Pointer (std::auto_ptr / unique_ptr) oder sogar ein Rohzeiger (versuchen, dies zu vermeiden, da es eine gemeinsame Quelle von Fehlern) und verwalten der Speicher manuell. Dann passieren Verweise oder Zeiger auf andere Objekte. Wenn das Eigentum ist die Smart-Pointer-Einrichtungen übergebene, um das Objekt an den neuen Eigentümer zu erhalten. Wenn das Eigentum wirklich geteilt wird (es gibt keine klaren Eigentümer des zugeordneten Objekts), dann können Sie shared_ptr verwenden und den Smart-Pointer-Deal mit der Speicherverwaltung lassen).

Warum versuchen Sie Zeiger willkürlich löschen? Jede dynamisch zugewiesenen Aufgabe wird in zugewiesen ein Ort, der von ein Eigentümer. Und es sollte sein, dass ein Eigentümer Verantwortung das Objekt, um sicherzustellen, wieder gelöscht wird.

In einigen Fällen können Sie wollen Transfer Eigentum an ein anderes Objekt oder eine Komponente, in diesem Fall die Verantwortung für das Löschen ändert sich auch.

Und manchmal, Sie wollen einfach nur über Eigentums- und Nutzungs shared Eigentum vergessen: Jeder, der die Objekt Aktien verwendet ownersip, und solange mindestens ein Benutzer vorhanden ist, sollte das Objekt nicht gelöscht werden.

Dann nutzen Sie shared_ptr.

Kurz gesagt, die Verwendung RAII. Versuchen Sie nicht, manuell löschen Objekte.

Es gibt einige sehr seltene Fälle, in denen Sie keine Smart-Pointer zu verwenden, möglicherweise in der Lage (wahrscheinlich mit altem Code zu tun), können aber nicht ein einfaches „ownership“ Schema entweder verwenden.

Stellen Sie sich vor Sie haben eine std::vector<whatever*> und einige der whatever* Zeiger auf das gleiche Objekt. Sichere Bereinigung beinhaltet Sie gewährleistet löschen nicht das gleiche, was auch immer zweimal - so ein std::set<whatever*> bauen, wie Sie gehen, und nur die Zeiger löschen, die nicht bereits in der Reihe sind. Sobald alle Spitz auf Objekte gelöscht wurden, können beide Behälter sicher auch gelöscht werden.

Der Rückgabewert von insert kann verwendet werden, um zu bestimmen, ob das eingefügte Element neu war oder nicht. Ich habe nicht das folgende (oder gebrauchten std :: set für eine Weile) getestet, aber ich denke, die folgende Recht ist ...

if (myset.insert (pointervalue).second)
{
  //  Value was successfully inserted as a new item
  delete pointervalue;
}

Sie sollten keine Projekte so gestalten, dass dies notwendig ist, natürlich, aber es ist nicht zu hart mit der Situation umgehen, wenn Sie es nicht vermeiden können.

Es ist nicht möglich zu wissen, ob der Speicher durch einen Zeiger verwiesen wird bereits gelöscht, wie in Ihrem Fall.
Wenn Sie nicht über eine Bibliothek mit Smart-Pointer verwenden können, die Referenzzählung zu tun, und Sie können Ihre eigene Referenzzählung Schema nicht implementieren (wenn in der Tat müssen Sie tun, was Sie in Ihrem Beitrag beschreiben) versuchen realloc auf den Zeiger zu nennen.
Ich habe in anderen Beiträgen gelesen, dass in Abhängigkeit von der Implementierung der Aufruf von realloc nicht abstürzen, sondern geben einen Null-Zeiger zurück. In diesem Fall wissen Sie, dass die von diesem Zeiger verweist auf Speicher freigegeben wurde.
Wenn dies funktioniert als eine schmutzige Lösung, wird es nicht tragbar sein, aber wenn Sie keine andere Wahl haben, versuchen Sie es. Je schlechter natürlich wird Ihre Anwendung zum Absturz bringen:)

Ich würde sagen, dass einige Male, intelligente Zeiger tatsächlich Ihre Anwendung verlangsamen können, albiet nicht viel. Was ich tun würde, ist ein Verfahren zu schaffen, etwa so:

void safeDelete(void **ptr)
{
  if(*ptr != NULL)
  {
     delete ptr;
     *ptr = NULL;
  }
}

Ich bin mir nicht sicher, ob ich es zu 100% richtig gemacht, aber was Sie tun, ist, dass Sie den Mauszeiger in diese Methode übergeben, die den Zeiger eines Zeigers nimmt, prüft sicher den Zeiger, um es verweist, nicht auf NULL, löscht dann das Objekt aus und stellt dann die Adresse auf 0 oder NULL. Korrigieren Sie mich, wenn dieser dies zu tun, nicht ein guter Weg, ich bin auch neu in diesem und jemand sagte mir, das war eine gute Möglichkeit, ohne zu überprüfen, kompliziert zu werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top