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

Yan*_*hao 8 c++ move unique-ptr

我的问题是关于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);
    }
 
    ...
};
Run Code Online (Sandbox Code Playgroud)

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

  1. 重置head->nextnullptr
  2. 设置head为新值;
  3. head销毁曾经指向的Node 对象;

上面的代码有效意味着 3 保证在 1 之后发生,否则链接仍然存在。

我想知道是否有一个书面规则来保证这样的顺序,或者它只是一个隐藏的实现细节,并且该示例可以正常工作。

The*_*ind 7

\n

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

\n
    \n
  1. 重置head->nextnullptr
  2. \n
  3. 设置head为新值;
  4. \n
  5. 销毁head所指向的Node对象;
  6. \n
\n
\n

在这种情况下,赋值运算符应该像head.reset(head->next.release())调用函数一样工作,根据[unique.ptr.single.asgn]/3

\n
\n
constexpr unique_ptr& operator=(unique_ptr&& u) noexcept;\n
Run Code Online (Sandbox Code Playgroud)\n

效果:reset(u.release())调用后接get_deleter() = std\xe2\x80\x8b::\xe2\x80\x8bforward<D>(u.get_deleter()).

\n
\n

无论如何,在这样的表达式中head->next.release()必须首先求值。reset按以下顺序执行其工作:

\n
    \n
  1. 将 的结果分配head->next.release()给存储的指针
  2. \n
  3. 删除指针先前存储的值
  4. \n
\n

这种操作顺序也是标准的一部分,[unique.ptr.single.modifiers]/3

\n
\n
constexpr void reset(pointer p = pointer()) noexcept;\n
Run Code Online (Sandbox Code Playgroud)\n

效果:将 p 赋给存储的指针,然后使用存储指针的旧值 来old_p计算if (old_p) get_deleter()(old_p);

\n
\n
\n

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

\n