Bonjour à tous,
Je fais appel à votre expertise.
J'ai besoin d'un vector pour contenir des objets, mais j'aimerais qu'à chaque push_back, les objets qu'ils contient ne soient pas détruits.
J'ai donc pensé à faire un vector de pointeur sur ces objets, de sorte que le resize du vector n'entraîne pas leur destruction.
Est ce une bonne idée ? J'ai lu sur developpez.com que faire un vector de pointeurs était redondant (le vector gérant lui même l'allocation dynamique en coulisse).
Merci d'avance ![]()
"(le vector gérant lui même l'allocation dynamique en coulisse)."
Non, le vector se charge lui même de l'allocation dynamique de son array interne, mais ils n'alloue pas ce qu'on lui push.
Quand tu push dans un vector, il fait une copie de l'objet.
En general on utilise un vector de pointeurs quand on ne peut pas copier/se permettre de copier les objets.
D'accord, donc ça pourrait m'éviter d'utiliser un constructeur par copie pour les objets contenus ?
Bonjour,
Si tu utilises un std::vector<MonObjet*>, la classe vector se contentera (par défaut) de gérer la place nécessaire pour stocker des MonObjet*. En revanche, il n'y aura pas d'appel ni aux constructeurs de MonObjet, ni à son destructeur (alors qu'il n'y a "que" ça avec un std::vector<MonObjet>).
Ok, merci pour l'éclairage.
Pour manier des objets lourds ou pénibles à copier, je peux donc faire
vecteur.push_back(new Objet());
?
Par exemple, oui.
Après, n'oublie pas qu'il faudra faire un delete un jour. ![]()
Héhé, ça ferait une belle fuite mémoire
Comme j'imagine qu'un simple vecteur.clear() ne ferra que mettre à zéro les pointeurs, je parcours le vecteur pour delete un à un ses objets.
Merci pour les précisions (^o^)/
Oui iterator et delete sur chaque objet, et après à la fin tu clear.
As-tu absolument besoin d'un vector? Si tu as juste besoin d’itérer, utilise un std::list, c'est en général une mauvaise idée d'utiliser un vector si on appelle souvent push_back.
Si tu a besoin de l'indexation en temps constant mais que tu n'a pas a tout prix besoin que les éléments soient stockés de manière contigus, pense à utiliser un std::deque: à la différence du vector, le push_back du deque ne réalloue pas de mémoire pour les objets précédemment insérés. Ca t'évitera les pointeur. Un seul désavantage: l'indexation est un poil plus lente.
Si tu est en C++11, pour éviter la recopie inutile lors du push_back, pense à la méthode emplace_back qui construit l'élement en place(elle existe aussi pour les vectors).
Enfin pense au smarts pointers du C++11 ou de boost(unique_ptr, shared_ptr et weak_ptr) si tu doit utiliser un vector pour ne pas t’embêter avec la mémoire, c'est un poil plus lent mais au moins il n'y a pas de leaks.
Merci pour tes suggestions hyrulink ![]()
J'avais essayé avec une std::list, mais les performances étaient un poil moins satisfaisante qu'avec les vecteurs (que je parcours à chaque frame).
Je ne connaissais pas cette propriété du std::deque, je vais m'y interesser, ça pourrait bien correspondre à mes besoins
Ceci dit j'aime bien travailler avec des pointeurs, ça me donne une impression de souplesse et de légèreté lors du traitement des données.
« Ceci dit j'aime bien travailler avec des pointeurs, ça me donne une impression de souplesse et de légèreté lors du traitement des données. »
au détail près que le C++, c'est fait pour éviter les pointeurs justement. ![]()
Les pointeur donnent peut-être de la souplesse dans certains cas mais de la légèreté, surement pas.
C'est à la fois lourd au niveau du code, bien que les smarts pointers résolvent en partie le problème et egalement lourd niveau perfs: un new/delete c'est pas gratuit.
Chris : pourrais tu développer, ce genre de questions m’intéressent
Hyrulink : je rechigne pas mal à utiliser boost et/ou les smarts pointers pour l'instant !
Les pointeurs, c'est LE DÉMON ! (si tu ne me crois pas, passe dans mon bureau déboguer le code de mon projet qui hélas regorge de mauvais usages des pointeurs
).
Partant de là, dès que tu peux faire sans pointeurs, fais sans pointeurs.
Le C++ t'offre pour ça trois choses qui remplacent bien des pointeurs :
1) les références.
Quand l'argument d'une fonction est gros, utilise un passage d'argument par référence (&), pas un passage par pointeur (*). De plus, si la fonction ne modifie par l'argument, utilise une référence constante (const&), ce qui améliore bien des choses en pratiques !
2) les objets.
De part leur nature, la gestion de la mémoire se fait dans les constructeurs et dans le destructeur. Si allouer de la mémoire est nécessaire, il y a des chances pour que tu es des pointeurs dans le code implantant ta classe. En revanche, le programme qui utilise le code ta classe est, lui, sans pointeurs.
3) les structures de données de la STL.
Souvent la solution pour stocker les données à manipuler tout au long du programme, ces structures masquent complétement les pointeurs sous-jacent (cf point 2).
Sinon, n'utilise pas boost. Ça t'apportera plus de soucis que de solutions. À ton niveau (enfin, c'est valable à tout niveau en fait), fais des choses simples. ![]()
Par simple curiosité, qu'est ce que tu as contre boost, Chris?
Certes l'apprentissage demande un investissement de temps mais les tutos de boost sont bien expliqués et une fois qu'on a appris on gagne un temps monstre a éviter de recoder tout un tas de choses qui auraient du avoir leur place dans la bibliothèque standard.
J'ai une expérience de boost où j'arrivais pas à coder un truc, boost à apporté une solution, et au final, quelques mois plus tard je m’aperçois qu'une solution simple et sans boost existait, il suffisait de revoir la conception.
Du coup maintenant j'évite de base d'utiliser boost ![]()
Un des points important du C++ est RIAA. Ca veut dire "Ressource Acquisition Is Initialization". En bref, ca veut dire "N'alloue pas de memoire toi meme, BOWDEL!!" (Lisez sur wikipedia[1] si vous voulez des details). Quand une variable est initialise, elle doit obtenir sa memoire d'elle meme. Quand la variable disparait parceque son contenant est detruit (scope-out, deallocation memoire), elle doit relacher sa memoire.
C'est une des raisons pour laquelle std::vector est souvent preferer a faire une allocation manuellement. Ca rejoins le commentaire de hyrulink:
"Enfin pense au smarts pointers du C++11 ou de boost(unique_ptr, shared_ptr et weak_ptr) "
C'est un vrai bon conseil. Je ne suis pas fan de boost (c'est trop gros, c'est trop le bordel, la doc est pourri, certain module obscure son bugge a mort), mais les smart pointers sont vraiment pratique. En vrai, c'est classique de reimplementer les smart_pointers soi meme.
[1] http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
hyrulink2: c'est essentiellement du gros hack pour Gourou à poil long codant des choses obscures nécessitant précisément du gros hack. Dans la vraie vie, on n'a pas besoin de ça (surtout que le C++11 offre des alternatives dans le cas présent).
Un grand merci d'avoir pris la peine de m'expliquer. Je ne savais absolument pas que les pointeurs étaient à éviter !
Du coup je vais revoir mes habitudes de programmation, parce que se passer des pointeurs demande généralement de réviser la conception de l'appli.