Что происходит с unique_ptr после std:: move()?

Этот код - это то, что я хочу сделать:

Tony& Movie::addTony()
{
    Tony *newTony = new Tony;
    std::unique_ptr<Tony> tony(newTony);
    attachActor(std::move(tony));
    return *newTony;
}

Мне интересно, могу ли я сделать это вместо этого:

Tony& Movie::addTony()
{
    std::unique_ptr<Tony> tony(new Tony);
    attachActor(std::move(tony));
    return *tony.get();
}

Но будет ли *tony.get() быть одним и тем же указателем или нулем? Я знаю, что могу проверить, но для чего это стандартная вещь?

Ответ 1

Нет, вы не можете этого сделать. Перемещение unique_ptr завершает его. Если бы это не так, то это не было бы уникальным. Я, конечно, предполагаю, что attachActor не делает ничего глупого:

attachActor(std::unique_ptr<Tony>&&) {
    // take the unique_ptr by r-value reference,
    // and then don't move from it, leaving the
    // original intact
}

Раздел 20.8.1, пункт 4.

Кроме того, u (объект unique_ptr) может, по запросу, передавать владение другим уникальным указателем u2. По завершении такого передачи, соблюдаются следующие постусловия:
  - u2.p равно предварительной передаче u.p,
    - u.p равно nullptr и
    - если состояние предварительной передачи u.d поддерживается, такое состояние было перенесено на u2.d.

Ответ 2

В стандарте говорится (§ 20.8.1.2.1 ¶ 16, добавлено выделение), что конструктор перемещения std::unique_ptr

unique_ptr(unique_ptr&& u) noexcept;

Создает a unique_ptr с помощью передачи права собственности от u до *this.

Поэтому после того, как вы перемещаете-строите временный объект, который передается в качестве аргумента в форму attachActor, ваш tony, tony больше не владеет объектом и, следовательно, tony.get() == nullptr. (Это один из немногих случаев, когда стандартная библиотека фактически делает утверждения о состоянии объекта с переездом от объекта.)

Однако желание вернуть ссылку может быть выполнено без использования голых new и необработанных указателей.

Tony&
Movie::addTony()
{
  auto tony = std::make_unique<Tony>();
  auto p = tony.get();
  attachActor(std::move(tony));
  return *p;
}

Этот код предполагает, что attachActor не будет отклонять свой аргумент на полу. В противном случае указатель p будет свисать после attachActor имеет return ed. Если на это нельзя положиться, вам придется перепроектировать свой интерфейс и использовать общие указатели.

std::shared_ptr<Tony>
Movie::addTony()
{
  auto tony = std::make_shared<Tony>();
  attachActor(tony);
  return tony;
}

Ответ 3

Я думаю, что вы не можете сделать тоже. Предполагая, что подпись attacActor: void attachActor (std :: unique_ptr x), как только вы вызовете его во время перемещения tony, attchActor будет владеть указателем и, как только он выйдет из области видимости, он удалит его. Поэтому после возвращения из attachActor, newTony должен был быть удален.
Я что-то здесь упускаю?