2009-08-21 3 views
5

Diciamo che ho una classe Object generica e una classe List generica. Voglio mantenere un elenco di questi oggetti. Devo memorizzarli come List<Object> o List<Object*>?Memorizzazione di un elenco di oggetti

se uso List<Object> e ho un metodo come:

if(some_condition) { 
    Object obj; 
    myObjectList.append(obj); 
} 

E la mia classe lista mantiene solo un riferimento all'oggetto, in modo il più presto che se dichiarazione termina, l'oggetto viene distrutto, e il l'oggetto che ho spinto non è valido. Quindi, finisco per fare qualcosa del tipo:

Object *obj = new Object; 
myObjectList.append(*obj); 

In modo che non venga distrutto. Ma ora gli oggetti sono indescrivibili, no? Perché ora sono memorizzati in modo sicuro nell'Elenco come Oggetti, non come puntatori agli Oggetti, quindi non posso richiamare l'eliminazione su di essi ... o verranno automaticamente distrutti quando vengono estratti dalla lista?

In questo caso, probabilmente dovrei usare List<Object*> e cancellarli dalla lista quando ho finito con loro, no?

Così confuso ... sono sicuro di avere un malinteso fondamentale qui da qualche parte.

+0

il problema è che si sta programmando come questo è java ... non lo è. –

+2

Beh, non vengo da uno sfondo Java o altro ... Sono solo un po 'ritardato stasera. – mpen

risposta

6

EDIT: Come menzionato in un commento boost::ptr_list è ancora meglio perché è più efficiente e ha lo stesso effetto netto come std::list<boost::shared_ptr<T> >.


EDIT: Accennate che si sta utilizzando Qt nel tuo commento. Se si utilizza> = 4.5 è possibile utilizzare Qt QList e QSharedPointer classi come questo:

QList<QSharedPointer<Object> > object_list; 
object_list.push_back(QSharedPointer<Object>(new Object)); 

ti consiglierei di utilizzare std::list<>. È anche probabile che tu voglia semplicemente archiviare i puntatori agli oggetti in modo che non vengano copiati tutto il tempo.

linea di fondo è così:

Diciamo che avere una classe denominata Object. Si dovrebbe fare questo:

std::list<boost::shared_ptr<Object> > object_list; 
object_list.push_back(new Object); 

per il C++ 11/14, senza bisogno di spinta, basta usare i puntatori intelligenti standard:

std::list<std::shared_ptr<Object>> object_list; 
object_list.push_back(std::make_shared<Object>()); 

Utilizzando i puntatori condivisi, gli oggetti vengono ripuliti automaticamente quando vengono rimossi dall'elenco (se non ci sono altri shared_ptr S che puntano anche ad esso).

Si potrebbe avere un list<Object *>. Ma dato il tuo livello di esperienza, sento che un puntatore contato di riferimento sarebbe molto più facile con cui lavorare.

In questo caso, forse dovrei usare List ed eliminarli dalla lista quando ho finito con loro, no?

Sì, questo è una valida opzione, ma mi raccomando puntatori intelligenti per evitare il "... ed eliminarli dalla lista ..." passo del tutto.


NOTA:

anche il codice di esempio che ha dato:

Object *obj = new Object; 
myObjectList.append(*obj); 

non è probabilmente quello che si voleva, questo rende un nuovo oggetto sul mucchio, si mette una copia di quello nella lista. Se non c'è più lo delete obj, allora c'è una perdita di memoria dal momento che i puntatori grezzi non sono automaticamente delete d.

+0

Beh, preferirei usare QList perché sto lavorando con Qt. Ma penso che il tuo suggerimento funzioni ancora. – mpen

+0

QList <> funzionerà in modo quasi identico a std :: list <>. Sono entrambi modelli e entrambi possono contenere puntatori/puntatori intelligenti. –

+0

QList <> supporta anche gli iteratori di stile STL in modo che siano belli e compatibili con gli algoritmi C++ generici. –

3

Nel primo caso l'oggetto viene copiato e solo l'originale viene distrutto. L'altra istanza è mantenuta nell'elenco.

Nella seconda versione è possibile utilizzare il distruttore Elenco per eliminare gli oggetti memorizzati.

+0

Oh ... vedo cosa stava succedendo. Perché con il codice su cui sto lavorando ho anch'io un altro puntatore nel mix ... Penso che uno non sia valido, e uno no. Questo spiega molto. – mpen

+2

Assicurati di avere un costruttore di copia "approfondito", oppure potresti ottenere risultati davvero imprevisti. – DeusAduro

1

Utilizzare i puntatori, come suggerito. Stai usando oggetti "generici", probabilmente una classe base, e la lista conterrà effettivamente alcuni oggetti derivati ​​castati alla base - questo significa che devi passare il puntatore all'oggetto originariamente creato. Altrimenti eliminerai tutto il polimorfismo.

Questo è

class Base 
{ 
public: 
    int x; 
    virtual int getData() const { return x; } 
}; 
class Derived : public Base 
{ 
public: 
    int y; 
    virtual int getData() const { return y; } 
}; 

Derived obj1; 
obj1.x = 1; 
obj1.y = 2; 

Base obj2 = obj1; 
cout << obj2.getData(); 

Questo stamperà 1, dal momento che obj2 è solo una copia di porzione di base di obj1 ed è davvero un esempio di Base.

1

Si potrebbe usare List, e poi quando è il momento di rilasciare un oggetto nella posizione x, si può usare qualcosa di simile

void erase_object(list* l, int i) { 
    delete (*list)[x] 
    list -> removeObj((*list)[x]); 
} 
2

come con "tutte" le cose non c'è una risposta - in del diavolo i dettagli di ciò che vuoi fare o quali sono i tuoi vincoli.

Se gli oggetti sono leggeri e non implicano la copia profonda, sarà più efficiente archiviare le piccole cose come copie. Altrimenti, il sovraccarico di puntatori intelligenti è più di quanto sia giustificato. Se sei polimorfico, puoi utilizzare gli elenchi di modelli.

se è più importante ridurre al minimo la copia ed eliminare il codice ridondante dalle istanze del modello, quindi utilizzare un elenco di puntatori intelligenti e condivisi.

Oppure utilizzare un elenco di puntatori nudi, utilizzare nuovo/Elimina e essere meticoloso con la proprietà del puntatore.

Qualsiasi elenco si comporterà come un elenco, quindi la scelta dell'implementazione dell'elenco dipende da fattori che non vengono enumerati qui.