Devrais-je stocker des objets entiers ou des pointeurs sur des objets dans des conteneurs?

StackOverflow https://stackoverflow.com/questions/141337

  •  02-07-2019
  •  | 
  •  

Question

Conception d’un nouveau système à partir de zéro. J'utiliserai la STL pour stocker des listes et des cartes de certains objets à longue durée de vie.

Question: Dois-je m'assurer que mes objets ont des constructeurs de copie et stocker des copies d'objets dans mes conteneurs STL, ou est-il généralement préférable de gérer la vie &? moi-même et juste stocker les pointeurs sur ces objets dans mes conteneurs STL?

Je me rends compte que les détails sont un peu courts, mais je recherche le & "théorique &"; mieux répondre si elle existe, car je sais que ces deux solutions sont possibles.

Deux inconvénients très évidents à jouer avec les pointeurs: 1) Je dois gérer l’affectation / désallocation de ces objets moi-même dans une portée au-delà du TSL. 2) Je ne peux pas créer d'objet temporaire sur la pile et l'ajouter à mes conteneurs.

Y a-t-il autre chose qui me manque?

Était-ce utile?

La solution

Puisque les gens ressentent l'efficacité d'utiliser des pointeurs.

Si vous envisagez d'utiliser un std :: vector et que les mises à jour sont rares et que vous effectuez souvent des itérations sur votre collection, il s'agit d'un type non polymorphe stockant un objet " copies " sera plus efficace puisque vous obtiendrez une meilleure localité de référence.

Otoh, si les mises à jour sont courantes, le stockage des pointeurs économisera les coûts de copie / déplacement.

Autres conseils

Cela dépend vraiment de votre situation.

Si vos objets sont petits et que leur copie est légère, le stockage des données dans un conteneur stl est simple et facile à gérer à mon avis, car vous n'avez pas à vous soucier de la gestion à vie.

Si vos objets sont volumineux et que le constructeur par défaut n’a pas de sens, ou que les copies d’objets sont coûteuses, alors stocker avec des pointeurs est probablement la solution.

Si vous décidez d'utiliser des pointeurs sur des objets, consultez Bibliothèque de conteneurs du pointeur Boost . Cette bibliothèque boost englobe tous les conteneurs STL à utiliser avec des objets alloués dynamiquement.

Chaque conteneur de pointeur (par exemple, ptr_vector) devient propriétaire d'un objet lorsqu'il est ajouté au conteneur et gère la durée de vie de ces objets pour vous. Vous accédez également à tous les éléments d'un conteneur ptr_ par référence. Cela vous permet de faire des choses comme

class BigExpensive { ... }

// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.push_back( new BigExpensive( "House", 15000000 );

// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

Ces classes encapsulent les conteneurs STL et fonctionnent avec tous les algorithmes STL, ce qui est très pratique.

Il existe également des fonctions permettant de transférer à l'appelant la propriété d'un pointeur dans le conteneur (via la fonction de libération dans la plupart des conteneurs).

Si vous stockez des objets polymorphes, vous devez toujours utiliser une collection de pointeurs de classe de base.

C’est-à-dire que si vous envisagez de stocker différents types dérivés dans votre collection, vous devez stocker les pointeurs ou être mangé par le démon de découpage.

Désolé de participer 3 ans après l'événement, mais une mise en garde ici ...

Lors de mon dernier grand projet, ma structure de données centrale était un ensemble d’objets assez simples. Environ un an après le début du projet, à mesure que les exigences évoluaient, je me suis rendu compte que l’objet devait en réalité être polymorphe. Il a fallu quelques semaines de chirurgie cérébrale difficile et désagréable pour que la structure de données soit un ensemble d'indicateurs de classe de base et pour gérer tous les dommages collatéraux liés au stockage d'objets, au casting, etc. Il m'a fallu quelques mois pour me convaincre que le nouveau code fonctionnait. Incidemment, cela m'a amené à réfléchir à la façon dont le modèle objet C ++ est bien conçu.

Sur mon grand projet actuel, ma structure de données centrale est un ensemble d’objets assez simples. Environ un an après le début du projet (ce qui est le cas aujourd'hui), j'ai réalisé que l'objet devait en fait être polymorphe. Retour sur le net, a trouvé ce fil et trouvé le lien de Nick vers la bibliothèque de conteneurs du pointeur Boost. C’est exactement ce que j’avais dû écrire la dernière fois pour tout régler, je vais donc tenter le coup cette fois-ci.

La morale, pour moi, en tout cas: si vos spécifications ne sont pas immuables dans la pierre, optez pour des indicateurs, et vous pourriez potentiellement vous épargner beaucoup de travail plus tard.

Pourquoi ne pas tirer le meilleur parti des deux mondes: créez un conteneur de pointeurs intelligents (tels que boost::shared_ptr ou std::shared_ptr ). Vous n'avez pas à gérer la mémoire ni à effectuer des opérations de copie volumineuse.

Généralement, stocker les objets directement dans le conteneur STL est préférable car il est le plus simple, le plus efficace et le plus simple pour utiliser l'objet.

Si votre objet a lui-même une syntaxe non copiable ou est un type de base abstrait, vous devrez stocker les pointeurs (le plus simple consiste à utiliser shared_ptr)

Vous semblez bien comprendre la différence. Si les objets sont petits et faciles à copier, stockez-les bien.

Sinon, je penserais à stocker des pointeurs intelligents (et non auto_ptr, un pointeur intelligent de comptage des références) sur ceux que vous affectez au tas. Évidemment, si vous optez pour des pointeurs intelligents, vous ne pouvez pas stocker les objets alloués à la pile temporaire (comme vous l'avez dit).

@ Torbj & # 246; rn insiste sur le découpage en tranches.

L'utilisation de pointeurs sera plus efficace, car les conteneurs ne feront que copier des pointeurs au lieu d'objets pleins.

Vous trouverez ici des informations utiles sur les conteneurs STL et les pointeurs intelligents:

Pourquoi est-il mauvais d'utiliser std :: auto_ptr < > avec des conteneurs standard?

Si les objets doivent être référencés ailleurs dans le code, enregistrez dans un vecteur boost :: shared_ptr. Cela garantit que les pointeurs sur l'objet resteront valides si vous redimensionnez le vecteur.

Ie:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

Si personne ne stocke de pointeurs sur les objets, ou si la liste ne grossit ni ne se rétrécit, stockez-les simplement en tant qu'objets anciens:

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol

Cette question me dérange depuis un moment.

Je compte sur le stockage des pointeurs, mais certaines exigences supplémentaires (enveloppes SWIG lua) pourraient ne pas s'appliquer à vous.

Le point le plus important de cet article est de le tester vous-même , en utilisant vos objets

.

Je l’ai fait aujourd’hui pour tester la vitesse d’appel d’une fonction membre sur une collection de 10 millions d’objets 500 fois.

La fonction met à jour x et y en fonction de xdir et ydir (toutes les variables de membre float).

J'ai utilisé un std :: list pour contenir les deux types d'objets et j'ai constaté que le stockage de l'objet dans la liste est légèrement plus rapide que l'utilisation d'un pointeur. D'autre part, les performances étaient très proches, il en va donc de la façon dont elles seront utilisées dans votre application.

Pour référence, avec -O3 sur mon matériel, les pointeurs prenaient 41 secondes et les objets bruts, 30 secondes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top