Pop-Methode der verknüpften Liste mit unique_ptr

Aug 20 2020

Ich betrachte die Implementierung einer einfach verknüpften Liste mit unique_ptronhttps://solarianprogrammer.com/2019/02/22/cpp-17-implementing-singly-linked-list-smart-pointers/. Meine Frage bezieht sich auf folgende Methode:

 3 struct List {
 4     List() : head{nullptr} {};
 5 
 6     // ...
 7 
 8     void pop() {
 9         if(head == nullptr) {
10             return;
11         }
12 
13         std::unique_ptr<Node> temp = std::move(head);
14         head = std::move(temp->next);
15     }
16 
17     // ...
18 };

Ich frage mich, warum das Provisorium hier benötigt wird? Warum konnten Sie nicht einfach tun head = std::move(head->next)? Liegt das daran, dass es zu einem Speicherleck führt? Gibt headbei einer Neuzuweisung unique_ptrautomatisch den aktuellen Speicher frei, auf den er zeigt?

Ich hatte den Eindruck, dass Smart Pointer narrensicher vor Speicherlecks sind. Es scheint in diesem Fall ein Speicherleck für das Original headzu geben, weil kein intelligenter Zeiger mehr darauf zeigt?

Antworten

4 RemyLebeau Aug 20 2020 at 07:36

Ich frage mich, warum das Provisorium hier benötigt wird?

Es wird nicht wirklich benötigt , aber es ist auch nicht schlecht zu bedienen.

Warum konnten Sie nicht einfach tun head = std::move(head->next)? Liegt das daran, dass es zu einem Speicherleck führt?

Sie können. In diesem Beispiel wird es kein Leck geben.

Gibt headbei einer Neuzuweisung unique_ptrautomatisch den aktuellen Speicher frei, auf den er zeigt?

Ja. Der alte Zeiger wird jedoch deleteerst nach der Übertragung des Besitzes des neuen Zeigers übertragen. Per CPReferenz:

https://en.cppreference.com/w/cpp/memory/unique_ptr/operator%3D

Überträgt das Eigentum von ran, *thisals ob durch einen Aufruf reset(r.release())gefolgt von einer Zuweisung von get_deleter()from std::forward<E>(r.get_deleter()).

https://en.cppreference.com/w/cpp/memory/unique_ptr/reset

Ersetzt das verwaltete Objekt.

  1. Gegeben current_ptrführt der von verwaltete Zeiger *thisdie folgenden Aktionen in dieser Reihenfolge aus:

    1. Speichert eine Kopie des aktuellen Zeigersold_ptr = current_ptr
    2. Überschreibt den aktuellen Zeiger mit dem Argumentcurrent_ptr = ptr
    3. Wenn der alte Zeiger nicht leer war, wird das zuvor verwaltete Objekt gelöscht
      if(old_ptr) get_deleter()(old_ptr).

So:

In dem Fall, in dem tempverwendet wird, wird der Zeiger auf den alten Knoten in headzuerst tempüber seinen Bewegungskonstruktor verschoben und zurückgesetzt head, um ein zu halten nullptr. Dann wird dieser Zeiger head.operator=aufgerufen und abgerufen. next.release()Und dann tempwird der Gültigkeitsbereich deleteverlassen und der alte Knoten wird aktiviert.

Falls tempnicht verwendet wird, head.operator=wird aufgerufen next.release(), der alte Zeiger gespeichert und durch den freigegebenen Zeiger und dann deletedurch den gespeicherten Zeiger ersetzt.

So oder so kein Leck.

Ich hatte den Eindruck, dass Smart Pointer narrensicher vor Speicherlecks sind.

Bei richtiger Anwendung ja.

Es scheint in diesem Fall ein Speicherleck für das Original headzu geben, weil kein intelligenter Zeiger mehr darauf zeigt?

Es gibt kein Leck, da immer unique_ptrauf den alten Knoten verwiesen wird, bis er pop()austritt und tempzerstört wird delete, wodurch der alte Knoten damit verbunden wird. Auch wenn tempweggelassen wird, wird der alte Knoten immer noch ordnungsgemäß zerstört, nachdem der Besitz seines nextZeigers übertragen wurde.