2013-07-04 14 views
29

Sto provando a utilizzare una classe derivata unique_ptr in una funzione che prende un unique_ptr in una classe base. Qualcosa di simile:unique_ptr a una classe base

class Base 
{}; 

class Derived : public Base 
{}; 

void f(unique_ptr<Base> const &base) 
{} 

… 

unique_ptr<Derived> derived = unique_ptr<Derived>(new Derived); 
f(derived); 

Se ho capito this answer correttamente, questo codice dovrebbe funzionare, ma provoca i seguenti errori di compilazione:

errore C2664: 'F': non può convertire il parametro 1 da 'std: : unique_ptr < _Ty>' a 'std :: const unique_ptr < _Ty> &'

IntelliSense: nessuna conversione definita dall'utente adatto da "std :: unique_ptr < derivata, std :: default_delete < Der ived >>" a "std :: const unique_ptr < Base, std :: default_delete < Base >>" esiste

Se cambio f prendere unique_ptr<Derived> const &derived, funziona benissimo, ma non è questo quello che voglio.

Sto facendo qualcosa di sbagliato? Cosa posso fare per aggirare questo problema?

sto usando Visual Studio 2012.

risposta

39

Sono disponibili tre opzioni:

  1. rinunciare alla proprietà. Questo lascerà la tua variabile locale senza accesso all'oggetto dinamico dopo la chiamata alla funzione; l'oggetto è stato trasferito al chiamato:

    f(std::move(derived)); 
    
  2. Modificare la firma del f:

    void f(std::unique_ptr<Derived> const &); 
    
  3. Cambiare il tipo di variabile:

    std::unique_ptr<base> derived = std::unique_ptr<Derived>(new Derived); 
    

    O, naturalmente, semplicemente:

    std::unique_ptr<base> derived(new Derived); 
    

    O anche:

    std::unique_ptr<base> derived = std::make_unique<Derived>(); 
    
  4. Aggiornamento: Oppure, come raccomandato nei commenti, non trasferire la proprietà a tutti:

    void f(Base & b); 
    
    f(*derived); 
    
+1

In tal caso, sto considerando di andare con 4. Utilizzare 'shared_ptr'. – svick

+2

Che ne dici di utilizzare solo un riferimento anziché un unique_ptr per la chiamata di funzione? – ltjax

+5

@svick, perché passare un puntatore intelligente alla funzione se non assume la proprietà del puntatore? Non è quello che puntano i puntatori intelligenti. –

8

Una soluzione possibile è quella di cambiare il digitare l'argomento come Base const* e passare invece derived.get(). Non c'è trasferimento di proprietà con unique_ptr const<Base>& (e lo unique_ptr non viene modificato), pertanto il passaggio a Base const* non modifica il significato.


Herb Sutter discute passare argomenti puntatore intelligente a lungo in Smart Pointer Parameters.Un estratto dal articolo collegato si riferisce a questa situazione esatta:

passaggio di un const unique_ptr<widget>& è strano, perché può solo accettare o null o un widget la cui vita sembra essere gestito nel codice chiamante tramite un unique_ptr, e il chiamato generalmente non dovrebbe preoccuparsi della scelta di gestione a vita del chiamante. Il passaggio widget* copre un superset rigoroso di questi casi e può accettare "null o widget" indipendentemente dal criterio di durata utilizzato dal chiamante.

+0

Non 'Base const *' significa che la funzione potrebbe memorizzare il puntatore da qualche parte? Anche se i puntatori intelligenti stanno cercando di evitarlo. – svick

+0

@svick, la funzione potrebbe memorizzare 'base.get()' altrettanto facilmente ('get()' è la funzione membro 'const'). – hmjd

+0

@svick No. I puntatori intelligenti servono a evitare perdite di memoria rendendo chiaro chi è il proprietario di un oggetto. Se si passa il puntatore raw come argomento a una funzione, basta dare l'accesso per leggerlo/modificarlo. I puntatori intelligenti devono evitare l'uso di raw 'new' e' delete', non di puntatori. – etam1024

Problemi correlati