OVH Cloud OVH Cloud

Quand utiliser la STL plutot qu'un tableau ?

21 réponses
Avatar
meow
Je suis en train d'impl=E9menter des carreaux de Bezier : =E0 peu de
chose pr=E8s, un entier n (le degr=E9) et un tableau de (n+1)*(n+2)/2
entr=E9es o=F9 stocker les "points de controle".
Bref, je me demandais s'il =E9tait pr=E9f=E9rable d'utiliser un type
vector ou un pointeur pour stocker mes points de controle... J'imagine
qu'il y a du plus comme du moins pour les deux solutions mais j'ai un
peu de mal =E0 =E9valuer tout =E7a. Pourrez vous m'aider ?

--Ben

10 réponses

1 2 3
Avatar
stephane_www
Arnaud Debaene wrote:
[...]

Peut-être, et *si il s'avère que c'est un problème*, on en tiendra compte...

Si la taille du tableau est connue à la compilation (c'est rare, mais çà
arrive), j'ai tendance à utiliser boost::array : je trouve que ca rend le
code plus lisible, et çà a un surcout pour ainsi dire nul.

Donc std::vector a un surcout non nul ;)


Avatar
meow
Tu peux aussi coder en assembleur pour gagner un peu de temps
d'execution et de mémoire.
Pas la peine d'etre méprisant, il y a un gap entre l'utilisation des

pointeurs et le passage à l'assembleur.

Mais le temps que tu vas passer en plus à coder et à debugger ton
programme pour gagner 10 malheureux petits % en performances, et bien
pendant ce temps là le PC moyen aura gagné en moyenne bien plus que ça.
C'est là le noeud de ma question : il y a donc un gain linéaire de

l'ordre de 10% au prix de la gestion de la mémoire... Ok, merci.

A l'heure actuelle 512 Mo de RAM coutent 50€uros soit grosso-modo une
heure-homme d'un ingénieur de SSI.
Cela n'a rien à voir avec le thread, mais pour info, le passage de

512Mo à 1Go sur ma machine (un portable SONY VAIO... Quelle idée !?
Plus jamais ça...) me coutera pas moins de 450€

J'en retiens donc que le gain en temps et en place, s'il existe, est
vraiment minime. Et qu'il vaut donc mieux utiliser la STL. Merci à
tous pour vos réponses.

Avatar
adebaene

Arnaud Debaene wrote:
[...]

Peut-être, et *si il s'avère que c'est un problème*, on en tiendr a compte...

Si la taille du tableau est connue à la compilation (c'est rare, mais çà
arrive), j'ai tendance à utiliser boost::array : je trouve que ca ren d le
code plus lisible, et çà a un surcout pour ainsi dire nul.

Donc std::vector a un surcout non nul ;)



Je n'ai pas dit qu'il était nul, j'ai dit qu'il était négligeable,
et encore je me suis mal exprimé. Il faudrait plutôt dire "99% du
temps le surcôut engendré par l'utilisation de std::vector n'a pas
d'impact sensible sur les performances du logiciel".

Si j'utilises parfois boost::array, c'est d'ailleurs plus pour
clarifier la sémantique (j'indique clairement que c'est un tableau de
taille fixe et connue) que pour des raisons de performances.

Arnaud


Avatar
Matthieu Moy
writes:

Si j'utilises parfois boost::array, c'est d'ailleurs plus pour
clarifier la sémantique (j'indique clairement que c'est un tableau de
taille fixe et connue) que pour des raisons de performances.


Je connais pas boost::array, mais il y a un truc chiant avec
std::vector, c'est que tu as besoin d'un constructeur de recopie, et
donc, on ne peut pas mettre des objets dont ce constructeur a été
désactivé (ou alors, on rajoute une couche de pointeurs, mais on
obtient un truc plutôt pire qu'un tableau "C").

--
Matthieu

Avatar
meow
Euh... je me rends compte que je n'avais pas conscience que les objets
stockés par vector devaient fournir un constructeur de recopie... En
meme temps cela parrait logique ! Sinon, comment faire pour stocker une
image d'un l'objet ? Une recopie mémoire brutale ?
Avatar
adebaene

writes:

Si j'utilises parfois boost::array, c'est d'ailleurs plus pour
clarifier la sémantique (j'indique clairement que c'est un tableau de
taille fixe et connue) que pour des raisons de performances.


Je connais pas boost::array,
http://www.boost.org/doc/html/array.html


mais il y a un truc chiant avec
std::vector, c'est que tu as besoin d'un constructeur de recopie, et
donc, on ne peut pas mettre des objets dont ce constructeur a été
désactivé (ou alors, on rajoute une couche de pointeurs, mais on
obtient un truc plutôt pire qu'un tableau "C").
Il doivent aussi être assignables.

Ce n'est pas "chiant", c'est normal, souhaitable (voire indispensable)
avec des conteneurs par valeur (comme le sont tous les conteneurs de la
STL et boost::array). Ceci-dit, je suis d'accord qu'il serait utile
d'avoir des conteneurs avec une sémantique par référence (ou quelque
chose s'en approchant) et des contraintes moindre. En attentdant mieux,
on peut toujours utiliser std::vector<boost::shared_ptr<MonType> >.

Arnaud


Avatar
Matthieu Moy
writes:

Il doivent aussi être assignables. Ce n'est pas "chiant", c'est
normal, souhaitable (voire indispensable) avec des conteneurs par
valeur (comme le sont tous les conteneurs de la STL et
boost::array).


Si tu n'as pas besoin de modifier les éléments de ton tableau, ce
n'est pas nécessaire. J'ai eu le cas avec des objets instanciés une
fois pour toute et constants (des ports SystemC pour ceux qui
connaissent). Un tableau à la C ne posait aucun problème, mais pas
moyen d'en faire un vector (le vector a besoin de pouvoir déplacer les
objets, donc d'en faire une copie puis une destruction).

Par contre, je suis d'accord sur le fait que le cas dont je parle est
peu courrant.

--
Matthieu

Avatar
meow
Euh... Je suis en train de me rendre compte d'un autre problème : y a
t'il moyen d'assigner une taille à mon vector sans pour autant
initialiser les valeurs qu'il contient. Je précises la question :

vector<Point> B(3); // B est un tableau de 3 points, tous initialisés
avec le constructeur par défaut de Point.

vector<Point> B(0);
vector.resize(3); // idem

vector<Point> B(0);
vector.reserve(3); // j'indiques la mémoire max dont j'aurai besoin
B[2].set(1,1,1,Point(1,0,2));// si j'ai bien compris ça peut marcher
comme ça peut planter... En tout cas c'est pas propre parce que la
taille de mon vector est toujours 0 !

J'aimerai donc savoir s'il y a un moyen de modifier *uniquement* la
taille du tableau sans rien toucher à son contenu. Ce n'est certes pas
propre puisque à ce moment la mémoire peut etre dans n'importe quel
état, mais dans la mesure où justement je fais un remplissage à la
main et à l'aide du subscript operator [] juste après je ne vois pas
la necessité d'initialiser !

Bref, meme si dans mon cas (je n'ai que peu d'objets à traiter) ce
n'est franchement pas un problème, il n'en reste pas moins que
lorsqu'on doit stocker un grand nombre d'objets et si ceux-ci sont
particulièrement complexes (contiennent eux memes d'autres objets,
voire des vector d'objets...), le fait d'appeller une cascade de
constructeurs par défauts puis de constructeurs de recopie peut
s'avérer lourdingue, non ?
Avatar
Arnaud Meurgues
meow wrote:

dans la mesure où justement je fais un remplissage à la
main et à l'aide du subscript operator [] juste après je ne vois pas
la necessité d'initialiser !


Dans ce cas, pourquoi reserve n'irait pas ?
Après, il suffit de remplir avec des push_back.

--
Arnaud

Avatar
adebaene

Euh... Je suis en train de me rendre compte d'un autre problème : y a
t'il moyen d'assigner une taille à mon vector sans pour autant
initialiser les valeurs qu'il contient. Je précises la question :

vector<Point> B(3); // B est un tableau de 3 points, tous initialisés
avec le constructeur par défaut de Point.

vector<Point> B(0);
vector.resize(3); // idem

vector<Point> B(0);
vector.reserve(3); // j'indiques la mémoire max dont j'aurai besoin
B[2].set(1,1,1,Point(1,0,2));// si j'ai bien compris ça peut marcher
comme ça peut planter... En tout cas c'est pas propre parce que la
taille de mon vector est toujours 0 !

J'aimerai donc savoir s'il y a un moyen de modifier *uniquement* la
taille du tableau sans rien toucher à son contenu. Ce n'est certes pas
propre puisque à ce moment la mémoire peut etre dans n'importe quel
état, mais dans la mesure où justement je fais un remplissage à la
main et à l'aide du subscript operator [] juste après je ne vois pas
la necessité d'initialiser !

Bref, meme si dans mon cas (je n'ai que peu d'objets à traiter) ce
n'est franchement pas un problème, il n'en reste pas moins que
lorsqu'on doit stocker un grand nombre d'objets et si ceux-ci sont
particulièrement complexes (contiennent eux memes d'autres objets,
voire des vector d'objets...), le fait d'appeller une cascade de
constructeurs par défauts puis de constructeurs de recopie peut
s'avérer lourdingue, non ?
Arrêtes de te faire des noeuds au cerveau avec les performances

jusqu'à ce que tu ais démontré qu'il fallait s'en préoccuper!
Quelques copies de structures "Point" en plus ou en moins ne feront
aucune différence sur ton application!

La solution *correcte* (c'est à dire avec un comportement défini par
la norme) et efficace c'est reserve suivi de push_back pour insérer
effectivement les éléments.

*Si* l'objet est particulièrement lourd (ce qui n'est pas ton cas!!!),
alors oui on évitera de faire des copies dans tous les sens, mais dans
ce cas, généralement, on ne fera pas un vector<MaClasseCompliquee>
mais un vector<boost::shared_ptr<MaClasseCompliquee> >, justement pour
éviter les copies.

Arnaud

1 2 3