Sagen wir, ich habe eine Klasse.
%Vor%Dann tue ich:
%Vor%Später, nachdem ich mit meinem Objekt fertig bin und ich sicher bin, dass dort keine anderen Benutzer für das Objekt sind.
Ist Folgendes sicher:
%Vor%Würde ich das Objekt ohne zusätzliche Zuweisungen zurücksetzen?
Ja, normalerweise ist es sicher. (Nicken Sie zu Maxim Yegorushkins Beobachtung über einen Fallfall)
Beachten Sie die Tippfehler-Meldung unter
Boost definiert die Dereferenz- und ->
-Operatoren als
Wenn diese detail
Bits aufgelöst sind, haben Sie dies
Sie haben es also direkt mit dem spitzen Objekt zu tun. Es gibt keine Proxies oder andere Konstrukte, die das, was Sie versuchen, beeinträchtigen könnten.
Da es sich um die angegebenen Daten handelt, lautet Ihr Code:
%Vor%Kann einen Tippfehler haben. Aber wenn du es beabsichtigst:
%Vor%Es wird aufgelöst nach
%Vor%Dies ist legal, und Sie haben Recht, dass es die zusätzliche Zuweisung vermeiden würde, die normalerweise bei einer Zuweisung anfällt.
Es gibt ein paar Möglichkeiten, dies zu tun. Sie können Placement neu verwenden, und dies ist aus zwei Gründen garantiert sicher:
Sie haben bereits den Speicher für das Objekt zugewiesen, damit Sie wissen, dass es korrekt skaliert und ausgerichtet ist.
shared_ptr
ist nicht invasiv; seine alleinige Verantwortung besteht darin, Referenzen zu zählen und bei Bedarf den Deleter aufzurufen.
Bedenken Sie jedoch, was passieren kann, wenn die Rekonstruktion des Objekts fehlschlägt, d. h. eine Ausnahme auslöst:
%Vor%Dann haben Sie ein Problem: Der Deleter kann auf einem nicht konstruierten Objekt aufgerufen werden, was höchstwahrscheinlich zu undefiniertem Verhalten führt. Ich sage "fast", weil der Deleter ein No-Op sein könnte, in diesem Fall wäre alles gut.
Sicherer, ich denke, würde einen neuen Wert in das vorhandene Objekt verschieben:
%Vor% Oder fügen Sie eine reset()
-Memberfunktion zu BigData
hinzu:
Dann ist es explizit, was Ihre wahre Absicht ist, und Sie müssen nicht so besorgt über Objektlebenszeiten sein.
Es ist sicher, wenn BigData
Konstruktor und Destruktor keine Ausnahmen auslöst und bigDataPtr
nicht zwischen Threads geteilt wird und keine Zeiger oder Referenzen auf dynamisch zugewiesene Mitglieder von BigData
(falls vorhanden) existieren.
Wenn der Destruktor eine Ausnahme auslöst, kann es sein, dass Sie ein teilweise zerstörtes Objekt erhalten (das Werfen von Destruktoren wird im Allgemeinen nicht empfohlen und Standardcontainer erfordern, dass Destruktoren von Elementen nicht geworfen werden).
Wenn der Konstruktor Sie wirft, kann es passieren, dass Sie das Objekt zerstören, aber kein neues erstellen.
Wenn bigDataPtr
zwischen Threads geteilt wird, die auch zu einer Race-Bedingung führen können, es sei denn, eine Sperrdisziplin wird verwendet.
Wenn Code an anderer Stelle Verweise oder Zeiger auf dynamisch zugewiesene Mitglieder von BigData
annimmt, wenn er ein neues BigData
erstellt, können seine dynamisch zugewiesenen Mitglieder anderen Adressen zugewiesen werden, so dass bestehende Zeiger und Verweise auf die Mitglieder ungültig werden / p>
Wenn Sie sich mit der zweifelhaften Dereferenzierung in new (&*bigDataPtr) BigData;
Anweisung beschäftigen, verwenden Sie stattdessen einen einfachen Zeiger:
Erstens, wenn der Konstruktor eine Klasse wirft und die Klasse nicht einfach zerstörbar ist, dann haben Sie ein Problem, da die shared_ptr
sie löschen möchte, was UB provozieren würde.
Sie müssen sich damit befassen, indem Sie entweder einen Notch-Konstruktor verwenden oder eine Ausnahme abfangen und verhindern, dass der Smart-Pointer das Objekt löscht. Da shared_ptr
keine release()
-Funktion hat, ist das leichter gesagt als getan. Sie könnten terminate()
aufrufen, wenn alles andere fehlschlägt, aber das macht Sie bei Ihren Benutzern nicht beliebt.
Wenn es keine anderen Verweise auf das Objekt gibt, funktioniert es, vorausgesetzt, die Klasse hat keine const
oder nicht-statische Referenzdatenelemente (einschließlich Membern von Membern). Der Grund ist 3,8 / 7:
Wenn nach der Lebensdauer eines Objekts und vor dem Speichern was das Objekt belegt, wird wiederverwendet oder freigegeben, ein neues Objekt ist an dem Speicherort erstellt, den das ursprüngliche Objekt belegt hat, a Zeiger, der auf das ursprüngliche Objekt zeigt ... kann verwendet werden manipuliere das neue Objekt, wenn ... der Typ des ursprünglichen Objekts ist nicht const-quali fi ziert, und, falls eine Klassenart vorhanden ist, keine nicht statisches Datenelement, dessen Typ const-quali fi ziert ist oder eine Referenz Geben Sie ...
ein
Beachten Sie, dass shared_ptr
nur einen solchen Zeiger enthält, mit dem das neue Objekt manipuliert werden kann. Das ist UB, wenn eine der Bedingungen in 3.8 / 7 kaputt ist. Der einzige, der möglicherweise kaputt ist, ist dieser, Sie haben den Rest mit dem, was Sie über Ihren Code gesagt haben, abgedeckt. Insbesondere ist es erforderlich, dass Sie das ursprüngliche Objekt als eine Instanz von BigData
, nicht eine von BigData
abgeleitete Klasse erstellt haben, da das neue Objekt den gleichen am meisten abgeleiteten Typ wie haben muss der alte.
Es gibt normalerweise robustere Möglichkeiten, ein Objekt zurückzusetzen. Implementieren Sie beispielsweise operator=
(Zuweisungsoperator kopieren oder verschieben), und schreiben Sie dann *bigDataPtr = BigData()
. Natürlich ist das vielleicht nicht ganz so schnell.
Tags und Links memory c++ performance