"sauberes" löschen von objekten auf die von mehreren pointern verwiesen wird
-
SciFi-N/A schrieb:
Wenn Du sowas machst :
delete a; a = NULL;
dann solltest Du keine Probleme haben.
Ja, ein löblicher Ansatz, nur löst er überhaupt nicht das Problem des OP
a = new irgendwas; b=a;//oder auch über einen Funktionsaufruf ala datavec.push_back(a); ... delete a;a=NULL;
^^ ab der Stelle kannst du nicht mehr über b auf dein Objekt zugreifen - und du hast keine Möglichkeit b mitzuteilen, daß seine Daten futsch sind.
-
Das stimmt, allerdings kann man es jetzt testen mit
if (b != NULL)
-
Nein, kannst du nicht - 'b' ist eine völlig eigenständige Variable, die sich vom "a=NULL" nicht beeindrucken läßt. (probier's aus, wenn du mir nicht glaubst)
-
Ich habe das mal auf die schnelle ausprobiert :
CCore *lpCore = NULL; CCore *lpCore2 = NULL; lpCore = new CCore(); lpCore2 = lpCore; SAFE_DELETE(lpCore); if (lpCore2 == NULL) cout << "NULL !" << endl; else cout << lpCore << endl << &lpCore << endl << lpCore2 << endl << &lpCore2 << endl; return 1;
Der Code bringt nicht das gewünschte Ergebnis, also habe ich mich getäuscht
CStoll hat recht und es ist eine eigenständige Variable.
-
Kleine Frage zwischendurch:
Heist das b zeigt nicht auf a sondern auf den selben neu reservierten Speicherplatz?
Und würde SciFi-N/A 's Vor schlag mit
test** b;
funktionieren?
-
|M| schrieb:
Kleine Frage zwischendurch:
Heist das b zeigt nicht auf a sondern auf den selben neu reservierten Speicherplatz?
Es wird klar, wenn man den Output der Console sieht (SAFE_DELETE auskommentiert):
00350840 0012FF70 00350840 0012FF6C
Ich hatte auch einen mächtigen Denkfehler.
-
Und wie wärs einfach mit ner Referenz auf den Orginalzeiger zu arbeiten?
... test* b; a=new test(); test*& b = a; ... if (a != NULL) delete b;
-
Das funktioniert :
CCore *lpCore = NULL; lpCore = new CCore(); CCore*& lpCore2 = lpCore; //SAFE_DELETE(lpCore); if (lpCore2 == NULL) cout << "NULL !" << endl; else cout << lpCore << endl << &lpCore << endl << lpCore2 << endl << &lpCore2 << endl; return 1;
Output :
00350840 0012FF70 00350840 0012FF70
Das ist allerdings eine exakte Kopie ohne eigene Adresse.
-
kompletter
test* b; a=new test(); test*& b = a; ... if (a != NULL) { delete b; a = NULL; }
-
[quote="SciFi-N/A"
Ich benutze für sowas immer mein Makro :#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
[/quote]
a) Der Test auf if(p) ist redundant, da er bereits durch delete durchgeführt wird.
b) Bevor man den Zeiger auf 0 setzt, sollte man sich überlegen, warum man dies tut. Macht man es aus purer Angst vor mehrfach-deletes, dann sollte man es lassen und stattdessen die Logik des Programms überprüfen. Eine Situation wo es hingegen Sinn macht, ist bei einer Komponente, die ein optionales Element verwaltet, dass dynamisch erzeugt und gelöscht werden kann.Zu der Originalfrage: shared-ptr sind eine (bequeme) Lösung, die aber in meinen Augen nicht immer die Default-Lösung sein sollte. Häufig ist eine Single-Owner-Strategie nicht nur schlanker, sondern auch einfacher. Man sucht sich eine Komponente, die für die Erzeugung/Löschung der Objekte zuständig ist. Alle anderen verwenden die Objekte nur. Diese Variante bietet sich allerdings nur an, wenn man dazu die Lebenszeit der Verwalter-Komponente nicht künstlich aufblähen muss.
-
@SciFi:
int* a=new int;int* b=a;
erzeugt zwei unabhängige Variablen, die beide auf den selben Heap-Block zeigen (und da a nichts davon weiß, daß jemand anderes auf seinen Speicher zeigt, kann es diesen Jemand auch nicht darüber benachrichtigen, daß der Speicher gelöscht wurde).
int* a=new int;int*& b=a;
erzeugt eine Variable und eine Referenz (Alias-Bezeichnung) für diese Variable - b ist logisch identisch mit a und bemerkt es auch, wenn a geändert/gelöscht wird. (allerdings sind Referenzen nicht überall sinnvoll/möglich - z.B. kannst du keine Referenzen in einen STL-Container packen (sind nicht kopierbar) und bist teilweise recht eingeschränkt mit der Nutzung (im Gegensatz zu einem Zeiger kannst du die Referenz nicht umbiegen))Smart-Pointer sind intelligenter als "normale" Pointer, deshalb können sie deren Probleme umgehen. Zum Beispiel führt der boost::shared_ptr einen Zähler mit, wie oft er kopiert wurde (damit weiß er zwar nicht, wer alles auf seinen Speicher zeigt, aber er weiß, wie oft auf diesen Block verwiesen wird - und "der letzte macht das Licht aus"), std::auto_ptr verwendet eine andere Methode - beim "kopieren" wird der Quellzeiger zurückgesetzt auf NULL, so daß es garantiert nur einen Zeiger gibt, der auf diesen Speicherbereich verweist* - und der ist auch für's Löschen zuständig.
(*) die nötige Disziplin vorausgesetzt
-
Danke für die Aufklärung. Ich hatte einen kleinen Denkfehler. Ich dachte, wenn b auf den Speicherbereich von a zeigt und a gelöscht wird (und zurückgesetzt), dann zeigt b auf a und a == NULL. Also müsste man im Umkehrschluss ebenfalls b auf NULL testen können. Mit sowas bekommt man schnell ein Brain-Overhead
-
Mit sowas bekommt man schnell ein Brain-Overhead
Nein, eigentlich garnicht schwer das. Bei dir hats nur noch nicht *click* gemacht. Müsste dir mal jmd. auf Papier aufzeichnen mit Speicherzellen und so. Eigentlich alles ganz einfach.
-
(allerdings sind Referenzen nicht überall sinnvoll/möglich - z.B. kannst du keine Referenzen in einen STL-Container packen (sind nicht kopierbar) und bist teilweise recht eingeschränkt mit der Nutzung (im Gegensatz zu einem Zeiger kannst du die Referenz nicht umbiegen))
Smart-Pointer (...)
(*) die nötige Disziplin vorausgesetzthmm... das is leider schlecht
das ist nämlich genau das, was ich z.Zt. mache... ich packe die ganzen pointer in verschiedene stl-container ... kann ich einfach ne eigene Pointer-container-klasse definieren? die könnte dann den pointer speichern und vorm stl verstecken....
Grüße, Tom
-
vorausgesetzt das es bei dem problem nur um eine bestimmte klasse handelt, koennte man doch auch den new und delete operator ueberladen.
intern vielleicht mit ner map die zusammenhaenge speichern und erst dann das object zerstoeren wenn das delete vom letzten drauf zeigenden pointer kommt?Meep Meep
-
yeus schrieb:
hmm... das is leider schlecht
das ist nämlich genau das, was ich z.Zt. mache... ich packe die ganzen pointer in verschiedene stl-container ... kann ich einfach ne eigene Pointer-container-klasse definieren? die könnte dann den pointer speichern und vorm stl verstecken....
Und wie bereits mehrfach erwähnt wurde, gibt es für so etwas Smart-Pointer: Bosst::shared_ptr<> dürfte genau das sein, was du hier benötigst. Und afair gibt es in der Boost-Bibliothek auch spezielle Pointer-Container.
(mit "Disziplin" meinte ich, daß es durchaus möglich ist, einen Smart-Pointer auszuhebeln - ist übel, ist gefährlich und sollte möglichst nicht weiter verfolgt werden)
@Meep: Ja, viel Spaß bei dem Versuch
operator new() und operator delete() arbeiten mit nacktem Speicher (und vor allem sind deine Daten schon futsch, wenn du im operator delete() überprüfen willst, ob du sie noch retten müsstest)