2009-08-21 15 views
5

Disons que j'ai une classe Object générique et une classe List générique. Je veux maintenir une liste de ces objets. Devrais-je les stocker comme List<Object> ou List<Object*>?Stockage d'une liste d'objets

Si j'utiliser List<Object> et j'ai une méthode comme:

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

Et ma classe de liste ne conserve qu'une référence à l'objet, dès que si la déclaration se termine, l'objet est détruit, et objet que j'ai poussé devient invalide. Alors, je finis par faire quelque chose comme:

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

Afin qu'il ne soit pas détruit. Mais maintenant les objets sont indélébiles, non? Parce que maintenant ils sont stockés en toute sécurité dans la liste comme des objets, pas des pointeurs vers des objets, donc je ne peux pas appeler supprimer sur eux ... ou seront-ils automatiquement détruits lorsqu'ils sont sortis de la liste?

Dans ce cas, je devrais probablement utiliser List<Object*> et les supprimer de la liste quand j'en ai fini avec eux, non? Si confus ... Je suis sûr que j'ai un malentendu fondamental ici quelque part.

+0

le problème est que vous programmez comme ceci est java ... ce n'est pas le cas. –

+2

Eh bien, je ne viens pas d'un arrière-plan Java ou quoi que ce soit ... Je suis juste un peu attardé ce soir. – mpen

Répondre

6

EDIT: Comme mentionné dans un commentaire boost::ptr_list est encore mieux, car il est plus efficace et a le même effet net comme std::list<boost::shared_ptr<T> >.


EDIT: Vous mentionnez que vous utilisez Qt dans votre commentaire. Si vous utilisez> = 4.5, vous pouvez utiliser les classes de Qt QList et QSharedPointer comme ceci:

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

Je vous recommandons d'utiliser std::list<>. Il est également probable que vous souhaitiez simplement stocker des pointeurs sur les objets afin qu'ils ne soient pas copiés tout le temps.

ligne est donc en bas:

Disons que vous avez une classe nommée Object. Vous devriez faire ceci:

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

C++ 11/14, pas besoin de coup de pouce, il suffit d'utiliser les pointeurs intelligents standard:

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

En utilisant des pointeurs partagés, les objets seront nettoyés automatiquement lorsqu'ils sont supprimés de la liste (s'il n'y a pas d'autre shared_ptr S pointant dessus). Vous pourriez avoir un list<Object *>. Mais compte tenu de votre niveau d'expérience, je pense qu'un pointeur compté de référence serait beaucoup plus facile pour vous de travailler avec.

Dans ce cas, je devrais probablement utiliser liste et les supprimer de la liste quand je suis fait avec eux, non?

Oui, cela est une option viable, mais je recommande fortement pointeurs intelligents pour éviter la « ... et les supprimer de la liste ... » étape tout à fait.


REMARQUE:

également le code exemple que vous avez donné:

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

est probablement pas ce que vous vouliez, cela fait un nouvel objet sur le tas, ils met une copie de cela dans la liste. S'il n'y a pas delete obj après cela, alors vous avez une fuite de mémoire puisque les pointeurs bruts ne sont pas automatiquement delete d.

+0

Eh bien, je préférerais utiliser QList comme je travaille avec Qt. Mais je pense que votre suggestion fonctionne toujours. – mpen

+0

QList <> fonctionnera presque de la même manière que std :: list <>. Ils sont tous les deux modélisés et les deux peuvent contenir des pointeurs/pointeurs intelligents. –

+0

QList <> prend également en charge les itérateurs de style STL afin qu'ils soient agréables et compatibles avec les algorithmes génériques C++. –

3

Dans le premier cas, l'objet est copié et seul l'original est détruit. L'autre instance est conservée dans la liste.

Dans la deuxième version, vous pouvez utiliser le destructeur de liste pour supprimer les objets stockés.

+0

Oh ... je vois ce qui se passait. Parce qu'avec le code sur lequel je travaille, j'ai un autre pointeur dans le mix aussi ... Je pense que l'un n'était pas valide, et l'autre non. Ça explique beaucoup. – mpen

+2

Assurez-vous d'avoir un constructeur de copie 'deep', sinon vous pourriez obtenir des résultats vraiment inattendus. – DeusAduro

1

Utilisez des pointeurs, comme cela a été suggéré. Vous utilisez des objets "génériques", probablement une classe de base, et la liste contiendra en fait des objets dérivés castés à la base - cela signifie que vous devez passer un pointeur vers l'objet créé à l'origine. Sinon, vous éliminerez tout le polymorfisme.

C'est

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

Ce imprimera 1, puisque obj2 est juste une copie de la partie de base de obj1 et est vraiment une instance de base.

1

Vous pouvez utiliser la liste, puis quand il est temps de désaffecter un objet à la position x, vous pouvez utiliser quelque chose comme

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

comme avec « tous » les choses il n'y a pas une réponse - la dans du diable les détails de ce que vous voulez faire, ou quelles sont vos contraintes.

Si les objets sont légers et n'impliquent pas de copie en profondeur, il sera plus efficace de stocker les petites choses en tant que copies. Sinon, la surcharge des pointeurs intelligents est plus que justifiée. Si vous êtes polymorphe alors vous pouvez utiliser des listes modèles.

S'il est plus important de minimiser la copie et d'éliminer le code redondant des instanciations de modèles, utilisez une liste de pointeurs partagés intelligents. Ou utilisez une liste de pointeurs nus, utilisez new/delete et soyez méticuleux avec la propriété de votre pointeur.

Toute liste agira comme une liste, donc le choix de l'implémentation de la liste dépend de facteurs que vous n'énumerez pas ici.