2014-11-10 14 views
16

Sto cercando di capire se è possibile creare una matrice di puntatori condivisi per tipi diversi. Per esempio, qualcosa di simile:Matrice di puntatori condivisi a diverse classi

vector<shared_ptr<**???**>> v; 
v.push_back(shared_ptr<int>(new int)); 
v.push_back(shared_ptr<MyClass>(new MyClass())); 

o in qualsiasi altro modo per passare shared_ptr senza conoscere il suo tipo.

+0

Hai provato a ottenere un puntatore da quel vettore? Come vuoi rilevare il tipo di cast di cui hai bisogno? - Rendi tutti gli elementi nel vettore ereditati da una classe base come "IObject". In quel caso conosci il tipo di vettore e il C++ ti permette di lanciare in sicurezza. – harper

+0

Non è una buona idea. – Ajay

+0

Sì, ma si richiede una matrice di shared_ptr <>. Una coppia è qualcosa di diverso e potrebbe essere utile. – harper

risposta

22

Supponendo di voler archiviare oggetti che non ereditano una classe comune, il modo più semplice che viene in mente è utilizzare boost::any.

Devi ancora essere sicuro di quale sia il tipo di ogni oggetto memorizzato in ciascun indice (ad esempio, per poter eseguire il corretto boost::any_cast).

Si consiglia di farlo anziché memorizzare i puntatori su void. Questo è il più vicino al modo semanticamente corretto di memorizzare "qualcosa che conosci il tipo ma il compilatore no", implicando un cast nel recuperare il valore.

Mentre sia (any e un puntatore void) funzionerà allo stesso modo (puntatore a parte), se si esegue il cast al tipo sbagliato, any un'eccezione bad_any_cast (IIRC), mentre con il puntatore void, ti ottenere un comportamento indefinito. Una semplice prova su Coliru ha prodotto a segfault.

+0

Grazie, quindi non c'è modo di fare quello che voglio con solo gli strumenti di C++ 11? –

+2

Beh, potresti provare a implementare una soluzione per questo, ma penso che finirà molto come "boost :: any'. Oh e' boost :: any' è una funzionalità di solo header, quindi non c'è nemmeno l'argomento di dover collegare a una lib extra. – JBL

+6

In realtà, quello che otterrete è indefinito comportamento.Questo mostra come un segfault _se sei fortunato_. – sbi

27

Altro tipo di sicurezza potrebbe essere:

/// header #include <boost/variant.hpp> 
typedef boost::variant < boost::shared_ptr <T1>, boost::shared_ptr <T2>, ... > VariantT; 

std::vector <VariantT> container; 
container.push_back (boost::shared_ptr <T1> (new T1)); // or boost::make_shared 
container.push_back (boost::shared_ptr <T2> (new T2)); // or boost::make_shared 

Più un'occhiata al Boost.Variant library.

+4

Si noti che questo approccio funziona solo se è possibile vincolare i tipi supportati dalla variante in fase di compilazione. – bpw1621

+4

@bpw: Come faresti diversamente? Non puoi lanciare (e questo si riduce sempre al casting a un livello o altro) a un tipo che non conosci al momento della compilazione. L'unico modo in cui riesco a pensare di trattare tipi sconosciuti al momento della compilazione è il polimorfismo del runtime, che richiede tipi correlati. – sbi

5

Proprio come qualsiasi tipo di puntatore fondamentale è convertibile in void*, qualsiasi shared_ptr convertirà a shared_ptr<void>:

vector<shared_ptr<void>> v; 
v.push_back(make_shared<int>()); 
v.push_back(make_shared<MyClass>()); 

Ora avete una vector di puntatori in comune completamente digitare-cancellati. Non si può fare molto di qualche cosa interessante con esso, però: dovreste sapere in qualche modo che tipi sono memorizzati in quali fessure della vector per convertirli indietro:

auto intptr = static_pointer_cast<int>(v[0]); 
auto myclass_ptr = static_pointer_cast<MyClass>(v[1]); 

Quindi, anche se è possibile per fare questo, non è terribilmente utile e probabilmente un'indicazione di un design rotto.

+21

No, questo non è quello che stai cercando. La genericità di 'void *' è sbagliata e ti porterà a scrivere codice ___buggy, difficile da risolvere e difficile da mantenere___. Molti dei costrutti del C++ sono stati inventati proprio per sbarazzarsi di questa vecchia abitudine. [la risposta di sfrehse] (http://stackoverflow.com/a/26844776/140719) è decisamente migliore. – sbi

+3

Bene, ho imparato qualcosa qui. Non sapevo che quel trucco era possibile. Certo che ora devo assicurarmi di non fare mai e poi mai qualcosa di stupido nel mio codice. Satus - ascolta per favore tutti quelli che ti fanno sapere che questo è un disegno rotto. Stai mescolando la C idiomatica con C++ idiomatico e l'unico risultato può essere un codice fragile. –

+0

@Satus Beh, sono certo contento di aver sbagliato :-) – cmaster

Problemi correlati