使用unique_ptr的链表的弹出方法

问题描述

我正在研究在https://solarianprogrammer.com/2019/02/22/cpp-17-implementing-singly-linked-list-smart-pointers/上使用unique_ptr的单链接列表的实现。我的问题与以下方法有关:

 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 };

我想知道为什么这里需要临时工?您为什么不能简单地head = std::move(head->next)?这是因为会导致内存泄漏吗?重新分配head后,unique_ptr自动释放它指向的当前内存吗?

我的印象是,智能指针可以防止内存泄漏。在这种情况下,似乎原来的head可能会发生内存泄漏,因为不再有指向它的智能指针了?

解决方法

我想知道为什么这里需要临时工吗?

这不是真正的所需,但使用它也不不好

为什么您不能简单地做head = std::move(head->next)?这是因为会导致内存泄漏吗?

可以。在此示例中不会泄漏。

重新分配head时,unique_ptr是否自动释放它指向的当前内存?

是的。但是,直到先传输新指针的所有权之后,才会delete使用旧指针。每个cppreference:

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

将所有权从r转移到*this,就像通过调用reset(r.release()),然后从get_deleter()分配std::forward<E>(r.get_deleter())一样。

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

替换托管对象。

  1. 给出current_ptr管理的指针*this,按此顺序执行以下操作:

    1. 保存当前指针old_ptr = current_ptr的副本
    2. 使用参数current_ptr = ptr覆盖当前指针
    3. 如果旧指针为非空,则删除先前管理的对象
      if(old_ptr) get_deleter()(old_ptr)

所以:

在使用temp的情况下,指向head中旧节点的指针将首先通过其move构造函数移至temp,将head重置为保持nullptr。然后head.operator=将调用next.release()并获取该指针。然后temp将超出范围,delete进入旧节点。

在不使用temp的情况下,head.operator=将调用next.release(),保存其旧指针并用释放的指针替换,然后delete保存指针。

两种方式均无泄漏。

给我的印象是,智能指针可以防止内存泄漏。

如果正确使用 ,是的。

在这种情况下,似乎原来的head可能会发生内存泄漏,因为不再有指向它的智能指针了吗?

没有泄漏,因为总是有unique_ptr指向旧节点,直到pop()退出并且temp被销毁,delete成为旧节点用它。即使省略了temp,在转移其next指针的所有权之后,旧节点仍会被正确销毁。