请考虑以下代码:
false
通过#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
的对象。
我很确定我在推理中遗漏了一些东西,但我无法弄清楚出了什么问题
这是安全的操作吗?标准在哪里让我放心?
答案 0 :(得分: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
。 -end note ]
因此,我们可以争辩存储指针将被替换,然后 旧存储指针将按此顺序删除。因此,一切都很好,定义明确。
此外,当您输入进入reset()
函数时,*foo.next
对象已经是release()
d,因此指向的对象不会被它摧毁。