关于涉及唯一指针的安全操作

About safe operations involving unique pointers

本文关键字:安全 操作 指针 唯一 于涉      更新时间:2023-10-16

考虑以下代码:

#include <memory>
struct Foo { std::unique_ptr<Foo> next; };
void f(Foo &foo) { foo = std::move(*foo.next); }
int main() {
Foo foo{};
foo.next = std::make_unique<Foo>();
foo.next->next = std::make_unique<Foo>();
f(foo);
}

通过执行foo = std::move(*foo.next);foo.next.next被移动到foo.next
如果foo.next作为第一步无效,则可以立即删除它所指向的对象。这将导致删除foo.next.next,也就是我试图移动到foo.next的对象
我很确定我的推理中遗漏了什么,但我搞不清楚出了什么问题
这是一个安全的操作吗?标准在哪里让我放心?

我认为这一切都非常安全。当您在foo上调用f()函数时,class Foo的移动赋值运算符将调用std::unique_ptr<Foo>::operator=(std::unique_ptr<Foo>&&)。现在,C++14标准,§20.8.1.2.3,逗号2,说:

效果:将所有权从u转移到*this,就像调用reset(u.release())然后调用get_deleter() = std::forward<D>(u.get_deleter())一样。

在§20.8.1.2.5,逗号4,我们发现reset():的行为

效果:p分配给存储的指针,然后如果存储指针的旧值old_p不等于nullptr,则调用get_deleter()(old_p)。[注意:这些操作的顺序很重要,因为对get_deleter()的调用可能会破坏*this--结束注释]

因此,我们可以争辩说,存储的指针将被替换,然后旧存储的指针将按此顺序被删除。因此,一切都很好,定义得很好。

此外,当您将输入reset()函数中时,*foo.next对象将已经是release()d,因此指向的对象不会被它破坏。