Ruft unique_ptr :: release () den Destruktor auf?

74

Ist dieser Code korrekt?

auto v =  make_unique<int>(12);
v.release();     // is this possible?

Entspricht es deleteeinem rohen Zeiger?

Zeukis
quelle

Antworten:

159

Nein, der Code verursacht einen Speicherverlust. releasewird verwendet, um den Besitz des verwalteten Objekts freizugeben, ohne es zu löschen:

auto v = make_unique<int>(12);  // manages the object
int * raw = v.release();        // pointer to no-longer-managed object
delete raw;                     // needs manual deletion

Tun Sie dies nur, wenn Sie einen guten Grund haben, den Rohspeicher ohne Sicherheitsnetz zu jonglieren.

Verwenden Sie zum Löschen des Objekts reset.

auto v = make_unique<int>(12);  // manages the object
v.reset();                      // delete the object, leaving v empty
Mike Seymour
quelle
9
Ich habe gesehen, wie Leute geschrieben haben, int* rawund int *rawdas war das erste Mal, dass ich gesehen habeint * raw
Cory Kramer
13
@Cyber: Es ist Geschmackssache. Ich betrachte das Zeigerqualifikationsmerkmal nicht als "angehängt" an den Typ oder die Variable, daher hänge ich es auch nicht an.
Mike Seymour
12
Wenn es traurig ist, dass sie sich entschieden haben, diese Funktionsnamen zu verwenden. So etwas detachwäre viel weniger irreführend als release.
Minexew
1
@eepp Würde das das Objekt zerstören oder einfach nur mögen release?
Tuket
1
Ich bin nicht einverstanden @nenchev. Ich denke , Zuordnung von nullptr ist mehr klar. Es gibt buchstäblich nichts anderes, als das Objekt zu löschen, auf das verwiesen wird (es ist unique_ptr), da es offensichtlich den aktuellen Wert durch nullptr ersetzt. Für reset () müssen Sie die Dokumente lesen, um genau zu wissen, was diese Funktion tut.
MadScientist
28

Ist dieser Code korrekt?

Nein. Verwenden Sie std::unique_ptr<>::reset()diese Option, um den internen Rohzeiger zu löschen:

auto v =  std::make_unique<int>(12);
v.reset(); // deletes the raw pointer

Danach std::unique_ptr<>::get()wird zurückgegeben nullptr(es sei denn, Sie haben einen Nicht- nullptrParameter angegeben std::unique_ptr<>::reset()).

Johann Gerell
quelle
20

Ist dieser Code korrekt?

Es ist nicht und wird auslaufen.

release()Lassen Sie den aufrufenden Code einfach den Besitz des Speichers zurückerobern, den unique_ptrer bis zum Aufruf gespeichert hat . Wenn Sie den von zurückgegebenen Zeiger nicht zuweisen release(), liegt nur ein Leck vor.

Ein explizites Löschen für a unique_ptrwäre reset(). Denken Sie jedoch daran, dass diese vorhanden unique_ptrsind, damit Sie den darin enthaltenen Speicher nicht direkt verwalten müssen. Das heißt, Sie sollten wissen, dass a unique_ptrden zugrunde liegenden Rohzeiger sicher löscht, sobald er den Gültigkeitsbereich verlässt.

Sie sollten also einen sehr guten Grund haben, eine manuelle Speicherverwaltung für ein automatisches Speicherverwaltungsobjekt durchzuführen.

JBL
quelle
12

release wird Ihren rohen Zeiger verlieren, da Sie ihn nichts zuweisen.

Es soll für so etwas wie verwendet werden

int* x = v.release();

Das heißt, ves verwaltet nicht mehr die Lebensdauer dieses Zeigers, sondern delegiert den Besitz des Rohzeigers an x. Wenn Sie nur releasenichts zuweisen, verlieren Sie den Rohzeiger.

Cory Kramer
quelle
Ah ich sehe. In meinem Code habe ich also .get()gefolgt .reset(), um Dinge auszutauschen, aber eigentlich möchte ich .release()folgen .reset(), um sicherzustellen, dass der .reset()Aufruf nicht deletedas alte Objekt ist. .release()führt dann die gleiche Funktion aus wie .get()nach dem Loslassen des Zeigers.
Andrew
oder vielleicht nicht, .reset()aber einfache Zuordnung nach .release().
Andrew
Ein .get()gefolgt von einem .reset()wird ein Problem verursachen. Das .get()gibt Ihnen einen nicht besitzenden Zeiger und .reset()ruft dann auf delete, daher ist Ihr Rohzeiger von getjetzt ein "baumelnder Zeiger" und der Zugriff darauf ist ein undefiniertes Verhalten.
Cory Kramer
2

Für beliebige Typen kann es etwas schwierig sein:

  unique_ptr<Foo> v = get_me_some_foo();  // manages the object
  Foo * raw = v.release();        // pointer to no-longer-managed object
  delete raw;

ist fast richtig.

  unique_ptr<Foo> v = get_me_some_foo();  // manages the object
  Foo * ptr = v.release();        // pointer to no-longer-managed object
  v.get_deleter() ( ptr );

dieser wäre in jeder Situation richtig; Möglicherweise ist ein benutzerdefinierter Deleter für den Typ Foo definiert, aber die Verwendung des vom unique_ptr-Objekt zurückgegebenen Deleters ist in allen Fällen sinnvoll.

MichaelMoser
quelle