2009-08-21 15 views
5

Digamos que tengo una clase de objeto genérica y una clase de lista genérica. Quiero mantener una lista de estos Objetos. ¿Debo guardarlos como List<Object> o List<Object*>?Almacenamiento de una lista de objetos

si uso List<Object> y tengo un método como:

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

Y mi clase de lista sólo mantiene una referencia al objeto, por lo que tan pronto como la sentencia if termina, el objeto es destruido, y el el objeto que empujé se convierte en inválido. De manera que termino haciendo algo como:

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

de modo que no quede destruida. Pero ahora los objetos no se pueden eliminar, ¿no? Porque ahora están almacenados de forma segura en la Lista como Objetos, no como punteros a Objetos, por lo que no puedo invocar eliminar en ellos ... ¿o se destruirán automáticamente cuando se extraigan de la lista?

En ese caso, probablemente debería usar List<Object*> y eliminarlos de la lista cuando haya terminado con ellos, ¿no?

Tan confundido ... Estoy seguro de que tengo un malentendido fundamental aquí en alguna parte.

+0

el problema es que estás programando como si esto fuera Java ... no lo es. –

+2

Bueno, yo no vengo de un fondo de Java ni nada ... Estoy un poco retrasado esta noche. – mpen

Respuesta

6

EDIT: Como se mencionó en un comentario boost::ptr_list es aún mejor, ya que es más eficiente y tiene el mismo efecto neto como std::list<boost::shared_ptr<T> >.


EDIT: Usted menciona que está utilizando Qt en su comentario. Si está utilizando> = 4.5 se puede utilizar QList y QSharedPointer clases de Qt como esto:

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

recomendaría utiliza std::list<>. También es probable que solo desee almacenar punteros a los objetos para que no se copien todo el tiempo.

Así que la línea de fondo es:

Supongamos que tenemos una clase llamada Object. Usted debe hacer esto:

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

para C++ 11/14, sin necesidad de impulso, sólo tiene que utilizar los punteros inteligentes estándar:

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

Mediante el uso de punteros compartidos, los objetos se limpiaron automáticamente cuando se eliminan de la lista (si no hay otros shared_ptr S también señalando).

Puede tener list<Object *>. Pero dado tu nivel de experiencia, creo que sería mucho más fácil para ti trabajar con un puntero de referencia.

En ese caso, probablemente debería utilizar lista y eliminarlos de la lista cuando he terminado con ellos, ¿no?

Sí, esta es una opción viable, pero recomiendo encarecidamente punteros inteligentes para evitar el "... y eliminarlos de la lista ..." paso completo.


NOTA:

también el código de ejemplo que diste:

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

probablemente no es lo que quería, esto hace que un nuevo objeto en el montón, se pone una copia de eso en la lista. Si no hay delete obj después de eso, entonces tiene una pérdida de memoria ya que los punteros crudos no son automáticamente delete d.

+0

Bueno, prefiero usar QList ya que estoy trabajando con Qt. Pero creo que tu sugerencia aún funciona. – mpen

+0

QList <> funcionará de manera casi idéntica a std :: list <>. Ambos tienen plantillas y ambos pueden contener punteros/punteros inteligentes. –

+0

QList <> también es compatible con los iteradores de estilo STL, por lo que son agradables y compatibles con los algoritmos genéricos de C++. –

3

En el primer caso, el objeto se copia y solo se destruye el original. La otra instancia se mantiene en la lista.

En la segunda versión puede usar el destructor de listas para eliminar los objetos almacenados.

+0

Oh ... veo lo que estaba pasando. Porque con el código en el que estoy trabajando, también tengo otro puntero en la mezcla ... Creo que uno fue inválido y el otro no. Eso explica mucho. – mpen

+2

Asegúrate de tener un constructor de copia "profunda", o podrías obtener resultados realmente inesperados. – DeusAduro

1

Utilice punteros, como se sugirió. Está utilizando objetos "genéricos", probablemente una clase base, y la lista en realidad contendrá algunos objetos derivados convertidos en base, lo que significa que debe pasar el puntero al objeto creado originalmente. De lo contrario, eliminarás todo el polimorfismo.

Eso es

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(); 

Esto imprimirá 1, ya que obj2 es sólo una copia de la parte de base del obj1 y es realmente una instancia de base.

1

Se puede utilizar la lista, y luego, cuando llega el momento de cancelar la asignación de un objeto en la posición x, se usaría algo así como

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

como con "todas las" cosas no hay una respuesta - en el diablo los detalles de lo que quiere hacer, o cuáles son sus limitaciones.

Si los objetos son livianos y no implican una copia profunda, será más eficiente almacenar las pequeñas cosas como copias. De lo contrario, la sobrecarga de punteros inteligentes es más de lo que se justifica. Si eres polimórfico, puedes usar listas de plantillas.

si es más importante minimizar la copia y eliminar el código redundante de las instancias de plantilla, luego use una lista de punteros inteligentes compartidos.

O utilice una lista de punteros desnudos, use new/delete y sea meticuloso con la propiedad de su puntero.

Cualquier lista actuará como una lista, por lo que la elección de la implementación de la lista depende de factores que no está enumerando aquí.

Cuestiones relacionadas