2014-10-11 14 views
20

In C++11 possiamo trasferire la proprietà di un oggetto a un altro unique_ptr utilizzando std::move(). Dopo il trasferimento della proprietà, il puntatore intelligente che ha ceduto la proprietà diventa null e get() ritorna nullptr.Trasferimento della proprietà dell'oggetto da un unique_ptr a un altro unique_ptr in C++ 11?

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

Quali sono le situazioni in cui questo sarà utile in quanto si trasferisce la proprietà ad un altro unique_ptr?

+4

Questo è tutto. I puntatori intelligenti nella libreria standard non dovrebbero essere visti come puntatori che sono automaticamente liberati, ma in termini di * proprietà *. Disponi di dati che possono essere "posseduti" solo da una singola entità, quindi utilizzare indicatori univoci. –

+4

È utile quando si lavora con dati non copiabili come thread o socket ed è necessario sostituirlo da un posto a altro (ad esempio, per inserirlo nel vettore). – wowofbob

risposta

2

per esempio se si chiama una funzione è possibile move tuo unique_ptr nella lista dei parametri in modo che possa essere una parte della vostra funzione di firma

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

è possibile 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 gestisce unique_ptr, con std::move si esegue il cast Nell'intero oggetto, non stai cambiando nulla di proprietà, non c'è nulla di particolare nello std::unique_ptr mentre usi std::move perché lo std::move non si preoccupa di nulla di specifico, come ho detto è un cast incondizionato e unique_ptr semplicemente viene castato, l'intero oggetto che è un'istanza di tipo unique_ptr<T> è castato.

Se si vuole parlare di un trasferimento di proprietà dell'oggetto puntato dal unique_ptr, si dovrebbe prendere in considerazione la swap forniti da std::unique_ptr<T> sé.

+1

'unique_ptr' trasferisce la proprietà dell'oggetto gestito quando ci si sposta in un altro' unique_ptr'. –

+0

@JonathanPotter che è semanticamente scorretto, 'move' non fa nulla, è solo un cast, la sua semantica riguarda la mutazione di un'espressione in un valore rvalore, non sulla proprietà di trasferimento nel caso di' unique_ptr', quando la chiamata di funzione capita, che 'unique_ptr' verrà spostato, questo è un effetto collaterale e se il tuo scopo è cambiare proprietà, questo è il modo più criptico di farlo con la semantica sbagliata, non farlo, usa' swap', ha la semantica giusta e fa esattamente ciò che vuoi. – user2485710

+0

Ad essere sincero non sono abbastanza sicuro di cosa intendi. Ma cosa pensi che succeda quando premi 'push_back' a' unique_ptr' in un 'vector' usando' move'? –

19

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

Diciamo che avete un certo tipo polimorfico Animal:

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

con sottoclassi concrete Cat e Dog:

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

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

E si desidera una semplice fabbrica che crea un animale sulla base di un valore richiesto di obbedienza . Quindi la fabbrica deve restituire un puntatore. Vogliamo che la fabbrica di animale domestico per trasferire la proprietà degli animali da compagnia creata per il chiamante in modo un tipo di ritorno ragionevole è 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 un House che sarà proprio l'animale poi si potrebbe desiderare di passare l'animale domestico nel costruttore di House. C'è un certo dibattito (see comments on this blog post) sul modo migliore per passare un unique_ptr a un costruttore, ma sarebbe simile a questa:

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 abbiamo poi "spostato" agli Stati variabile.

Il codice chiamante potrebbe somigliare:

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

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

Live demo

+0

È meglio cambiare il costruttore per prendere un riferimento al valore r in unique_ptr? Per esempio. Casa (std :: unique_ptr && animale domestico). Quindi non avresti bisogno della chiamata std :: move() nella lista di inizializzazione per pet_? – jfritz42

+1

@ jfritz42 Un riferimento al valore r è esso stesso un valore l, quindi è ancora necessario il 'std :: move'. [Provalo] (http://coliru.stacked-crooked.com/a/42b8222989a16651). –

+0

Buon punto! A proposito, sembra un nuovo idioma in C++. Mi chiedo se gli sia stato dato un nome da qualcuno ancora. Il "trasferimento della proprietà idiom"? – jfritz42