2017-02-09 9 views
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.
Я почти уверен, что в моих рассуждениях что-то не хватает, но я не могу понять, что случилось.
Безопасная операция? Где стандарт меня успокаивает?

ответ

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 примечание]

Таким образом, мы можем утверждать, что хранится указатель будет заменен и затемстарый хранится указатель будет удален, в таком порядке. Таким образом, все хорошо и четко определено.

Кроме того, когда вы будете ввести в функцию reset(), то *foo.next объект уже был release() d, поэтому заостренный объект не будет уничтожен вместе с ним.