c++ - operator - rvalue reference




Trasferimento della proprietà dell'oggetto da un unique_ptr a un altro unique_ptr in C++ 11? (2)

In C++11 possiamo trasferire la proprietà di un oggetto a un altro unique_ptr usando std::move() . Dopo il trasferimento della proprietà, il puntatore intelligente che ha ceduto la proprietà diventa null e get() restituisce nullptr.

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

Quali sono le situazioni in cui ciò sarà utile poiché trasferisce la proprietà su un altro unique_ptr ?


Le seguenti situazioni implicano il trasferimento della proprietà da un unique_ptr a un altro: il ritorno da una funzione e il passaggio come parametro a una funzione come un costruttore.

Di 'che hai del tipo polimorfico Animal :

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

con sottoclassi di cemento Cat and Dog :

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

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

E tu vuoi una fabbrica semplice che crei un animale domestico basato sul valore richiesto dell'obbedienza. Quindi la fabbrica deve restituire un puntatore. Vogliamo che la fabbrica di animali domestici trasferisca la proprietà dell'animale domestico creato al chiamante in modo tale che un ragionevole tipo di ritorno sia 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>();
} 

Ora, diciamo che vogliamo creare una House che possieda l'animale domestico, allora potremmo voler passare l'animale domestico nel costruttore della House . C'è un po 'di dibattito ( vedi commenti su questo post del blog ) su come meglio passare un unique_ptr a un costruttore, ma sarebbe simile a questo:

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

Abbiamo passato il unique_ptr al costruttore e lo abbiamo "spostato" sulla variabile membro.

Il codice chiamante potrebbe assomigliare a qualcosa:

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

Dopo aver costruito la House , la variabile pet sarà nullptr perché abbiamo trasferito la proprietà dell'animale domestico alla House .

Dimostrazione dal vivo


ad esempio, se chiami una funzione, puoi move tuo unique_ptr nell'elenco dei parametri in modo che possa far parte della firma della tua funzione

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

puoi chiamare foo con

foo( std::move(myPtr) );

Nota che std::move è un cast incondizionato e unique_ptr è un oggetto con uno stato, e una parte di quello stato è il puntatore che sta gestendo unique_ptr , con std::move stai lanciando l'intero oggetto, non sei veramente cambiando qualcosa sulla proprietà, non c'è nulla di strano in std::unique_ptr mentre si usa std::move perché std::move non si preoccupa di nulla di specifico, come ho detto è un cast incondizionato e unique_ptr viene semplicemente castato, l'intero oggetto che è un'istanza di tipo unique_ptr<T> è castato.

Se vuoi parlare di un trasferimento di proprietà dell'oggetto puntato da unique_ptr , dovresti considerare lo swap fornito da std::unique_ptr<T> stesso.





move-semantics