Подтвердить что ты не робот

Перенос права собственности на объект с одного unique_ptr на другой unique_ptr в С++ 11?

В C++11 мы можем передать право собственности на объект на другой unique_ptr, используя std::move(). После передачи прав собственности смарт-указатель, который уступил собственности, становится null и get() возвращает nullptr.

std::unique_ptr<int> p1(new int(42));
std::unique_ptr<int> p2 = std::move(p1); // Transfer ownership

Каковы ситуации, когда это будет полезно, поскольку оно переносит право собственности на другой unique_ptr?

4b9b3361

Ответ 1

Следующие ситуации включают перенос права собственности с одного unique_ptr на другой: возврат из функции и передача в качестве параметра функции, такой как конструктор.

Скажем, у вас есть полиморфный тип Animal:

struct Animal {
  virtual ~Animal() {}
  virtual void speak() = 0;
};

с конкретными подклассами Cat и Dog:

struct Cat : Animal {
  void speak() override { std::cout << "Meow!\n"; }
};

struct Dog : Animal {
  void speak() override { std::cout << "Woof!\n"; }
};

И вам нужен простой factory, который создает домашнее животное на основе требуемого значения послушания. Затем factory должен вернуть указатель. Мы хотим, чтобы домашнее животное factory передало право собственности на созданное домашнее животное вызывающему, поэтому разумный тип возврата std::unique_ptr<Animal>:

std::unique_ptr<Animal> createPet(double obedience) {
  if (obedience > 5.0)
    return std::make_unique<Dog>();
  return std::make_unique<Cat>();
} 

Теперь, скажем, мы хотим создать House, который будет владеть домашним животным, тогда мы, возможно, захотим передать домашнее животное в конструктор House. Существует некоторая дискуссия (см. Комментарии к этому сообщению в блоге) о том, как лучше передать конструктору unique_ptr, но он будет выглядеть примерно так

class House {
 private:
  std::unique_ptr<Animal> pet_;
 public:
  House(std::unique_ptr<Animal> pet) : pet_(std::move(pet)) {}
};

Мы передали unique_ptr в конструктор и затем "переместили" его в переменную-член.

Код вызова может выглядеть примерно так:

  auto pet = createPet(6.0);
  House house(std::move(pet));

После построения House переменная pet будет nullptr, потому что мы передали права собственности на домашнее животное на House.

Живая демонстрация

Ответ 2

например, если вы вызываете функцию, вы можете move ваш unique_ptr в списке параметров, чтобы она могла быть частью вашей сигнатуры функции

foo ( std::unique_ptr<T>&& ptr )

вы можете вызвать foo с помощью

foo( std::move(myPtr) );

Обратите внимание, что std::move - это безусловный листинг, а unique_ptr - объект с состоянием, а часть этого состояния - это указатель, которым управляет unique_ptr, при std::move вы бросаете весь объект, вы ничего не меняете о правах собственности, нет ничего особенного в std::unique_ptr при использовании std::move, потому что std::move на самом деле не заботится ни о чем конкретном, так как я сказал, что это безусловный перевод, а unique_ptr просто получает casted, весь объект, являющийся экземпляром типа unique_ptr<T>, забрасывается.

Если вы хотите поговорить о передаче права собственности на объект, указанный вашим unique_ptr, вы должны рассмотреть swap, предоставленный std::unique_ptr<T> сам.