2013-08-23 13 views
7

Supponiamo di avere una classe chiamata foo che eredita da una classe denominata bar.Qual è il modo corretto di convertire uno std :: unique_ptr in uno std :: unique_ptr in una superclasse?

Ho un std::unique_ptr in un'istanza di foo e voglio passarlo a una funzione che richiede solo std::unique_ptr<bar>. Come posso convertire il puntatore in modo che funzioni nella mia funzione?

+0

è 'foo' un'istanza polimorfica? – Mahesh

+2

Esegui qualsiasi funzione che non si interessa da dove proviene la memoria o che cosa succede dopo, prendi i parametri per riferimento (o puntatore raw se può essere nullo). –

+1

@NeilKirk: funziona per la funzione, ma è un caso d'uso ragionevole per memorizzare 'unique_ptr ' in una raccolta. E se la funzione deve memorizzarlo ... –

risposta

27

è possibile convertire un rvalue std::unique_ptr<foo> a un std::unique_ptr<bar>:

std::unique_ptr<foo> f(new foo); 
std::unique_ptr<bar> b(std::move(f)); 

Ovviamente, il puntatore sarà di proprietà di b e se b viene distrutta bar necessità di avere un distruttore virtual.

-1

Non è possibile, perché violerebbe la unique_ptr regola più semplice: deve esserci una sola istanza che contiene un dato puntatore, e il unique_ptr ha piena proprietà di esso (quando va fuori portata, il pointee è cancellato).

unique_ptr<T> e unique_ptr<U> (dove U : T) non sono compatibili, come hai visto.

Per shared_ptr, per il quale è possibile avere più istanze, c'è std::static_pointer_cast che si comporta proprio come un static_cast, tranne che accetta un shared_ptr e restituisce un altro (ed entrambi puntano allo stesso oggetto).

Se è assolutamente necessario utilizzare uno unique_ptr, sarà necessario creare una funzione che prima rinnega l'attuale unique_ptr e lo inserisce in uno nuovo del tipo corretto. Potrebbe anche essere necessario eseguire la conversione opposta dopo la chiamata di funzione.

+1

+1. per completezza, 'std :: dynamic_pointer_cast <>' e 'std :: const_pointer_cast <>' esistono per altre conversioni puntatore comuni. – justin

+3

Certo che puoi, devi solo trasferire la proprietà, ovviamente. –

+0

@MatthieuM. "Se hai assolutamente bisogno di usare un unique_ptr, dovrai creare una funzione che prima rinnega il tuo unique_ptr corrente e lo inserisce in uno nuovo del tipo giusto." Il mio punto era che un 'unique_ptr ' non può associarsi a un riferimento 'unique_ptr '. Anche il trasferimento della proprietà non è sicuro per le eccezioni. – zneak

0

è possibile utilizzare questa sintassi:

std::unique_ptr<parent> parentptr = std::unique_ptr<child>(childptr); 

Oppure si può usare std::move.

L'altra opzione è quella di emettere puntatore crudo, ma è necessario modificare una funzione:

void func(const parent* ptr) 
{ 
    // actions... 
} 
func(*childptr); 

Ecco un buon articolo su puntatori intelligenti e passandolo a funzioni: http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters.

2

Nulla di speciale è richiesto a causa dell'ereditarietà. È necessario utilizzare std::move per passare l'unique_ptr a una funzione, ma questo è vero anche se i tipi di corrispondenza:

#include <memory> 

struct A { 
}; 

struct B : A { 
}; 

static void f(std::unique_ptr<A>) 
{ 
} 

int main(int,char**) 
{ 
    std::unique_ptr<B> b_ptr(new B); 
    f(std::move(b_ptr)); 
} 
Problemi correlati