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

sky*_*ack 11 c++ unique-ptr c++14

请考虑以下代码:

#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);
}
Run Code Online (Sandbox Code Playgroud)

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

Pao*_*o M 7

我认为这一切都非常安全.当您打开f()函数时foo,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()剐,这样尖锐的物体不会与它被破坏.