2015-09-23 60 views
5

Sono un novizio C++ relativo che tenta di convertire un progetto esistente da puntatori grezzi, con un complicato protocollo di gestione della memoria, fino all'uso di C++ 11 shared_ptr. Nel complesso sta andando molto bene, e io penso Capisco come lo shared_ptr funzioni in termini di semantica del movimento, riferimenti di valore, ecc. Roba buona.Errore strano nel tentativo di eseguire un shared_ptr swap()

Tuttavia, ho riscontrato un errore strano che non capisco e non so come risolvere. Prima un po 'di storia. Ho una gerarchia di classi radicata in una classe base astratta denominata EidosValue, e una classe denominata EidosValue_Int_vector è (indirettamente) una sottoclasse concreta di che:

class EidosValue 
class EidosValue_Int : public EidosValue 
class EidosValue_Int_vector : public EidosValue_Int 

Il mio codice trasporti a generalmente EidosValue, ma a volte, soprattutto quando si crea un nuovo valore, ho bisogno di gestire una sottoclasse specifica.

ho fatto typedef per le shared_ptr s per queste classi, in modo da avere:

typedef std::shared_ptr<EidosValue> EidosValue_SP; 
typedef std::shared_ptr<EidosValue_Int_vector> EidosValue_Int_vector_SP; 

tra gli altri. OK, quindi ora al centro del problema. Ho una funzione che restituisce un EidosValue_SP che crea. A seconda della logica all'interno della funzione, potrebbe creare una delle diverse sottoclassi concrete di EidosValue. Così faccio qualcosa di simile:

EidosValue_SP MyClass::MyMethod(...) 
{ 
    EidosValue_SP result; 

    if (...) 
    { 
     EidosValue_Int_vector_SP int_result_SP = make_shared<EidosValue_Int_vector>(); 
     ... do subclass-specific stuff with int_result_SP... 
     result.swap(int_result_SP); 
    } 
    else (...) 
    { 
     ...similar logic for other subclasses... 
    } 

    ...other shared logic... 
    return result; 
} 

Il problema è con la chiamata swap(). Viene visualizzato un messaggio di errore: "Non-const lvalue reference to type 'shared_ptr<EidosValue>' cannot bind to a value of unrelated type 'shared_ptr<EidosValue_Int_vector>'". Questo è sconcertante dal momento che EidosValue_Int_vector non è un "tipo non correlato", è una sottoclasse pubblica di EidosValue, e il codice qui lo sa. Se scrivo result = make_shared<EidosValue_Int_vector>();, il compilatore non ha alcun problema con quello, quindi sa chiaramente che i tipi sono correlati e compatibili. Semplicemente non mi piace nel contesto di swap() per qualche motivo. In altri punti del mio progetto sono stato in grado di fare semplicemente un return int_result_SP;, con un tipo di reso dichiarato di EidosValue_SP, e che ha funzionato bene - il compilatore è felice di considerare EidosValue_Int_vector_SP come EidosValue_SP in quel contesto - ma io posso Lo facciamo qui a causa della logica condivisa nella parte inferiore della funzione.

Sono un po 'limitato nella mia implementazione qui perché questo codice è un collo di bottiglia e ha bisogno di correre veloce (e sì, so che da effettivamente strumentare il codice, e sì, conta davvero). Quindi è essenziale usare make_shared per evitare una doppia allocazione, e vorrei anche fortemente evitare un incremento/decremento del conteggio quando porto il puntatore da int_result_SP al risultato; Non voglio che ci sia un momento nel tempo in cui ci sono due shared_ptr che puntano alla nuova istanza. Quindi swap() sembra la strada più ovvia da fare; ma sono bloccato da questo errore del compilatore. Perché sta accadendo e come posso risolverlo? Grazie!

APPENDICE:

Oh, riflettendo questo ulteriore Scommetto che so il motivo per cui l'errore sta accadendo. swap() non ha obiezioni a mettere il EidosValue_Int_vector nel EidosValue_SP, ma è avere un problema con mettere il EidosValue nel EidosValue_Int_vector_SP; in quella direzione i tipi non sono compatibili. Non ci avevo pensato in questo modo poiché result non ha alcun valore (ad esempio, è nullptr, credo); ma ovviamente lo swap() non lo sa. OK, quindi se questo è il problema, la domanda rimane: come posso effettuare il trasferimento mantenendo il codice velocemente - non facendo un conto inc/dec e non allontanandomi dall'uso di make_shared?Ora che ho capito il problema (credo) sembra probabile che ci sia solo alcune API o trucco che ho trascurato ...

risposta

4

Questo è esattamente ciò che è std::move. Uso:

result = std::move (int_result_SP); 
5

Non è possibile swap perché, anche se EidosValue_Int_vectorè unEidosValue l'isn Converse' è vero

+0

Sì, l'ho capito subito dopo aver cliccato. Vedi l'addendum che ho appena pubblicato. La domanda rimane come far funzionare il mio codice. – bhaller

+2

just 'result = int_result_SP;'. Non è necessario lo swap – qehgt

+0

"mantenendo il codice veloce" - cosa ti fa pensare che l'assegnazione stia rendendo il tuo codice ** non ** veloce? – YePhIcK

Problemi correlati