2010-12-04 23 views
10

ich mit einem Vektor von Zeigern auf andere Objekte darin, so etwas wie dieses ein Objekt haben:Kann ein nicht neues Objekt gelöscht werden?

class Object { 
    ... 
    vector<Object*> objlist; 
    ... 
}; 

Nun werden Objekte in diesen beiden Möglichkeiten zur Liste hinzugefügt werden:

Object obj; 
obj.objlist.push_back(new Object); 

und

Object name; 
Object* anon = &name; 
obj.objlist.push_back(anon); 

Wenn ein Destruktor machen, die einfach ist

~Object { 
    for (int i = 0; i < objlist.size(); i++) { 
     delete objlist[i]; 
     objlist[i] = NULL; 
    } 
} 

Wird es negative Folgen in Bezug auf sein, wenn es versucht, ein Objekt zu löschen, die nicht mit neuem erstellt wurde?

+0

Ich weiß, dass es mit einem Iterator besser sein könnte, aber "objlist" war ursprünglich und Array und ich bin nicht dazu gekommen, die Schleife zu ändern. –

Antwort

28

Ja, es wird schädliche Wirkungen sein.

Sie müssen nicht delete ein Objekt, das nicht mit new zugeordnet wurde. Wenn das Objekt auf dem Stapel zugewiesen wurde, hat Ihr Compiler bereits einen Aufruf seines Destruktors am Ende seines Bereichs generiert. Das bedeutet, dass Sie den Destruktor zweimal aufrufen, was möglicherweise sehr negative Auswirkungen hat.

Neben dem zweimaligen Aufruf des Destruktors versuchen Sie auch, einen Speicherblock freizugeben, der nie zugewiesen wurde. Der new-Operator legt die Objekte vermutlich auf dem Heap ab; delete erwartet, das Objekt in derselben Region zu finden, die der new-Operator ihnen gibt. Ihr Objekt, das nicht mit new zugewiesen wurde, befindet sich jedoch auf dem Stapel. Dies wird sehr wahrscheinlich Ihr Programm zum Absturz bringen (wenn es nicht bereits nach dem zweiten Aufruf des Destruktors abstürzt).

Sie werden auch in tiefe Schwierigkeiten geraten, wenn Ihr Object auf dem Haufen länger als Ihr Object auf dem Stapel lebt: Sie werden eine hängende Referenz irgendwo auf dem Stapel bekommen, und Sie werden falsche Ergebnisse/Absturz bekommen Das nächste Mal, wenn Sie darauf zugreifen. Die allgemeine Regel, die ich sehe, ist, dass Sachen, die auf dem Stapel leben, auf Sachen verweisen können, die auf dem Haufen leben, aber Sachen auf dem Haufen sollten nicht auf Sachen auf dem Stapel verweisen wegen der sehr hohen Chancen, dass sie den Stapel überleben werden Objekte. Und Zeiger auf beide sollten nicht miteinander vermischt werden.

+0

Ich verstehe. Gibt es eine Möglichkeit, sicherzustellen, dass wenn das Objekt zerstört wird, alles in objlist, das dort mit new eingefügt wurde, gelöscht wird, und sonst nichts? –

+1

@ Keand64 Es gibt keine Sprachfunktion, um Ihnen dort zu helfen. Sobald Sie einen Zeiger haben, können Sie nicht (ohne plattformabhängige dunkle Magie/unsichere Operationen) wissen, ob er irgendwo auf dem Stapel oder auf dem Heap zeigt. Es ist generell eine schlechte Idee, Objekte, die auf dem Stapel liegen, und Objekte, die auf dem Haufen leben, zu mischen. Ihre beste Wette wäre es, für alle "new" zu verwenden. – zneak

+0

@ Keand64: Was Sie tun sollten, ist den gleichen Code verantwortlich für die 'neue' ing wie für die' Löschung' zu machen. Bei Containern lassen Sie den Container beides, indem Sie explizit alles kopieren, was in den Container eingefügt wird. (Dies schützt Sie auch vor dem aufrufenden Code, so dass das zugespitzte Ding nicht in den Geltungsbereich fällt.) ** Schreiben Sie aber trotzdem keine eigenen Container **; Die Standardbibliothek bietet, was Sie brauchen. –

1

Dies wird nicht funktionieren - wenn Sie ein Objekt, das nicht von new zugewiesen wurde Sie die Regeln oder die Operator verletzt haben.

Wenn Sie Ihre Vektorspeicher Objekte haben müssen, die gelöscht werden kann oder nicht müssen Sie müssen irgendwie den Überblick über das halten. Eine Option besteht darin, einen intelligenten Zeiger zu verwenden, der verfolgt, ob das auf das Objekt zeigende Objekt dynamisch ist oder nicht. Zum Beispiel shared_ptr<> können Sie ein deallocator Objekt angeben, wenn die shard_ptr<> konstruieren und wie die Dokumentation erwähnen:

Zum Beispiel kann ein „no-op“ deallocator ist nützlich, wenn ein shared_ptr auf ein statisch zugewiesene Objekt zurückzukehr

Sie sollen jedoch immer noch vorsichtig sein, wenn Hinweise auf automatische Variablen vorbei - wenn die Lebensdauer des Vektors länger als die Lebensdauer der Variablen ist, dann wird es irgendwann Müll beziehe werden.

3

Nein, können Sie nur delete was Sie new ed

Object* anon = &name; 

Wenn Name den Gültigkeitsbereich verlässt, werden Sie einen ungültigen Zeiger in Ihrem Vektor haben.

1

Was Sie eigentlich fragen ist, ob es sicher ist, ein Objekt zu löschen, das nicht über new über den Operator delete zugewiesen wurde, und wenn ja, warum?

Leider wird dies durch einige andere Probleme in Ihrem Code verschleiert. Wie bereits erwähnt, wenn Name den Geltungsbereich überschreitet, werden Sie mit einem ungültigen Zeiger enden.

Siehe zneak's answer für, warum Ihre ursprüngliche Frage nicht zu einer sicheren Operation führt, und warum der Bereich für Name tatsächlich von Bedeutung ist.

Verwandte Themen