移动 unique_ptr:重置源与销毁旧对象。

8

我的问题是关于https://en.cppreference.com/w/cpp/memory/unique_ptr中的示例。

struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
 
    std::unique_ptr<Node> head;
 
    ~List()
    {
        // destroy list nodes sequentially in a loop, the default destructor
        // would have invoked its `next`'s destructor recursively, which would
        // cause stack overflow for sufficiently large lists.
        while (head)
            head = std::move(head->next);
    }
 
    ...
};

head = std::move(head->next) 时,会发生三件事情:

  1. head->next 重置为 nullptr
  2. head 设置为新值;
  3. 销毁 head 原来指向的 Node 对象。

上述代码之所以能够正常工作,是因为 3 一定会在 1 之后发生,否则链式结构仍然存在。

我想知道是否有书面规定来保证这种顺序,还是这只是一个隐藏的实现细节,这个例子只是偶然能够正常工作。

1个回答

7
head = std::move(head->next)时,会发生三件事情:
  1. head->next重置为nullptr
  2. head设置为新的值;
  3. 销毁head原来指向的Node对象。
在这种情况下,赋值运算符应该像调用head.reset(head->next.release())函数一样工作,根据[unique.ptr.single.asgn]/3
constexpr unique_ptr& operator=(unique_ptr&& u) noexcept;

Effects: Calls reset(u.release()) followed by get_deleter() = std​::​forward<D>(u.get_deleter()).

在这种表达式中,head->next.release()无论如何都必须先评估。 reset按以下顺序执行其工作:
  1. head->next.release()的结果分配给存储的指针
  2. 删除指针以前存储的值
这些操作的顺序也是标准的一部分,[unique.ptr.single.modifiers]/3
constexpr void reset(pointer p = pointer()) noexcept;

Effects: Assigns p to the stored pointer, and then, with the old value of the stored pointer, old_p, evaluates if (old_p) get_deleter()(old_p);


长话短说 - 你的理解是正确的,并且得到了标准的保证。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接