涉及唯一指针的安全操作

11

请考虑以下代码:

#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 的那个对象。
我很确定我的推理中漏掉了什么,但我想不出哪里错了。
这个操作是安全的吗?标准在哪里保证了这一点?
1个回答

7
我认为这一切都是绝对安全的。当您在foo上调用f()函数时,class Foo的移动赋值运算符将调用std::unique_ptr::operator=(std::unique_ptr&&)。现在,根据C++14标准,§20.8.1.2.3,逗号2,它说:
效果:将所有权从u转移到*this,就好像通过调用reset(u.release())然后调用get_deleter() = std::forward(u.get_deleter())来完成。
在§20.8.1.2.5,逗号4中,我们找到了reset()的行为:
效果:将p赋给存储的指针,然后如果存储的旧指针old_p不等于nullptr,则调用get_deleter()(old_p)。【注意:这些操作的顺序很重要,因为对get_deleter()的调用可能会销毁*this。—end note】
因此,我们可以认为存储的指针将被替换,然后按顺序删除旧存储的指针。因此,一切都很好定义。
此外,当您进入reset()函数时,*foo.next对象已经被release(),因此指向的对象不会随其一起被销毁。

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