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
?
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
.
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.