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

问题描述 投票:0回答:1

我的问题是关于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 之后发生,否则链接仍然存在。

我想知道是否有一个写下来的规则来保证这样的顺序,或者它只是一个隐藏的实现细节,这个例子就可以了。

c++ move unique-ptr
1个回答
1
投票

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;

效果:调用

reset(u.release())
然后是
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;

效果:将p赋值给存储指针,然后用存储指针的旧值

old_p
,求值
if (old_p) get_deleter()(old_p);


长话短说——你的理解是正确的,并由标准保证

© www.soinside.com 2019 - 2024. All rights reserved.