web-dev-qa-db-fra.com

Transférer la propriété d'un objet d'un unique_ptr à un autre unique_ptr en C ++ 11?

Dans C++11, Nous pouvons transférer la propriété d'un objet à un autre unique_ptr En utilisant std::move(). Après le transfert de propriété, le pointeur intelligent qui a cédé la propriété devient null et get() renvoie nullptr.

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

Dans quelles situations cela sera-t-il utile car il transfère la propriété à un autre unique_ptr?

31
Roy

Les situations suivantes impliquent le transfert de propriété d'un unique_ptr à un autre: retour d'une fonction, et passage en paramètre à une fonction comme un constructeur.

Disons que vous avez un type polymorphe Animal:

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

avec des sous-classes concrètes Cat et Dog:

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

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

Et vous voulez une usine simple qui crée un animal de compagnie en fonction d'une valeur d'obéissance requise. Ensuite, l'usine doit renvoyer un pointeur. Nous souhaitons que l'animalerie transfère la propriété de l'animal créé à l'appelant. Un type de retour raisonnable est donc 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>();
} 

Maintenant, disons que nous voulons créer un House qui sera propriétaire de l'animal, alors nous pourrions vouloir passer l'animal dans le constructeur de House. Il y a un débat ( voir les commentaires sur ce billet de blog ) sur la meilleure façon de passer un unique_ptr à un constructeur, mais cela ressemblerait à ceci:

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

Nous avons passé le unique_ptr dans le constructeur et l'ont ensuite "déplacé" vers la variable membre.

Le code appelant pourrait ressembler à ceci:

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

Après avoir construit le House, la variable pet sera nullptr car nous avons transféré la propriété de l'animal au House.

Live demo

27
Chris Drew

par exemple, si vous appelez une fonction, vous pouvez move votre unique_ptr dans la liste des paramètres pour qu'il puisse faire partie de la signature de votre fonction

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

vous pouvez appeler foo avec

foo( std::move(myPtr) );

Notez que std::move est une distribution inconditionnelle et unique_ptr est un objet avec un état, et une partie de cet état est le pointeur que ce unique_ptr gère, avec std::move vous transformez l'intégralité de l'objet, vous ne changez rien à la propriété, il n'y a rien de particulier à propos de std::unique_ptr en utilisant std::move car std::move ne se soucie pas vraiment de quelque chose de spécifique, comme je l'ai dit, c'est un casting inconditionnel et unique_ptr est simplement casté, l'objet entier qui est une instance de type unique_ptr<T> est casté.

Si vous souhaitez parler d'un transfert de propriété de l'objet pointé par votre unique_ptr, vous devriez considérer le swap fourni par std::unique_ptr<T> lui-même.

4
user2485710