2016-05-29 3 views
-1

Я пытаюсь впервые использовать unique_ptr вырастить бинарное дерево, которое в основном работает как следующее:unique_ptr становится пустым после перемещения

void growTree(unique_ptr<Node> root){ 
//do some calculations 
root->value = "some value" 
     for(int i=0;i<2;i++){ 
      unique_ptr<Node> child(new Node); 
      growTree(move(child)); 
      root->children.push_back(move(child)); 
    } 
    } 

Однако, я обнаружил, что указатель «ребенок» становится пусто, прежде чем я верну их обратно до root->children. Почему он утрачивает свои ценности после рекурсии? Что я здесь делаю неправильно? Спасибо!

EDIT1: Теперь я понял, что не могу использовать unique_ptr для получения ожидаемого значения после его перемещения, так как я могу это сделать (вырастить дерево) с помощью умного указателя?

+6

Уникальная вещь уже не в одной руке, если вы переместите ее в другую сторону. Кажется, это работает по назначению. –

+0

'growTree (move (child))' действительно оставляет ребенка пустым, так почему же он не будет пустым на следующей строке? – stijn

+0

«unique_ptr становится пустым после переезда» - Yeees. Что еще вы ожидаете от * уникального * _ptr ?? –

ответ

2

Это совершенно нормально:

Перед push_back, вы движетесь child с std::move. Это буквально означает, что вы отдаете child на номер growTree, вам больше не нужен.

После перемещения child больше не указывает на исходный объект (потому что у другого объекта есть указатель на него, вы его переместили).


Если вы хотите изменить child, вы должны передать его в качестве ссылки, так что growTree можно изменить в Nodechild указывает на, без child потери указатель на него:

void growTree(std::unique_ptr<Note>& node); 
1

Когда вы перемещаете что-то кому-то еще, у вас больше нет перемещенного материала. Почему вы ожидаете этого?

После того, как вы переместите unique_ptr в вызов growTree, исходный объект теперь в действительном, но порожнем состоянии (другие объекты часто быть в действительном, но неустановленном состоянии и, конечно, не первоначальное состоянием и должен не использовать еще раз). Ожидается, и ваш код будет ошибкой из-за попыток использовать его снова.

+1

* «действительное, но неопределенное состояние» * - Состояние «unique_ptr» не является неопределенным после его перемещения. Он равен нулю, и вы можете использовать его снова. –

+0

@Benjamin Lindley В стандарте говорится: «Объекты типов, определенные в стандартной библиотеке C++, могут быть перемещены из (12.8). Операции перемещения могут быть явно указаны или неявно сгенерированы.Если не указано иное, такие перемещенные объекты помещаются в действительное, но неопределенное состояние. » –

+0

Термин, используемый, например, cppreference, является * действительным, но неопределенным состоянием * и объясняется как * То есть, только функции без предварительных условий, такие как как оператор присваивания, можно безопасно использовать на объекте после того, как он был перемещен из * – stijn

2

После того как вы перейдете от объекта, он концептуально пуст. Вот почему перемещение может быть более эффективным, чем копирование, потому что вы можете украсть ресурсы, которые затем исчезли. Исключением является переход от объекта дважды без указания нового значения. Кроме того, unique_ptr имеет уникальное право собственности на объект, поэтому может быть только один, поэтому вы не можете передать его как growTree, так и root->children.

Для решения проблемы вы должны решить, кому принадлежит child. std::move ребенок там и сохранит устойчивую ссылку на это место в другом месте. Если место зависит от времени выполнения, вы можете вместо этого использовать shared_ptr.

Смежные вопросы