OVH Cloud OVH Cloud

boucle for sur std::vector [debutant]

48 réponses
Avatar
AG
Bonjour,

je débute avec l'utiliation des vecteurs de la stl, et je me demandais
comment écrire une boucle for. J'ai vu dans les news une méthode assez
courante :



std::vector<int> n;

for(std::vector<int>::iterator i=n.begin();i!=n.end();i++)
{
}

Je trouve cette méthode lourde à écrire. Plus simplement j'aurais vu
(entre autre) :

std::vector<int> n;

for(int i=0;i<n.size();i++)
{
}


Que choisir ? Si je n'ai pas besoin de l'iterator dans la boucle, la
seconde solution est-elle meilleure (plus lisible, plus simple, plus
rapide ? )

AG.

8 réponses

1 2 3 4 5
Avatar
Olivier Azeau
AG wrote:
J'ai une classe RandInt qui me permet de générer un vecteur "n"
d'unsigned int tiré "aléatoirement"

Je veux ensuite transformer ce vecteur en vecteur de doubles "d" compris
entre 0 et 1, en divisant mon vecteur "n" par la plus grand valeur
d'unsigned int possible (appelons là RandIntMax)

je suis bien obligé de faire quelque chose du genre :

std::vector<unsigned int> n(20);
std::vector<double> d(20);
unsigned int RandIntMax;


J'ai probablement mal formulé mon interrogation.
Ce qui me gêne dans de tels exemples c'est que l'intention du
programmeur n'est pas lisible.

Si dans le contexte de l'application les "unsigned int" vont toujours de
paire avec les "double", c'est à dire une relation 1-1 (quand on change
la valeur des int, on change celle des double), alors
std::vector<RandValue> me parait, en première approche, plus approprié
car une classe regroupant une paire de valeurs int et double va
permettre de mieux mettre en évidence les opérations réalisées sur ces
valeurs.
Si on a une relation 1-n (le même vecteur d'unsigned int sert
successivement à créer divers vecteurs de double) alors on ne peut que
garder les 2 vecteurs séparés mais dans un tel cas ils n'appartiennent
plus à la même classe car il y a création d'un vecteur à partir de
l'autre (et dans un tel cas je ne comprends pas pourquoi on
initialiserait le vecteur de double *avant* le calcul de la division par
RandIntMax)

Et il y a probablement d'autre cas, mais tout ce que j'essaie de dire
c'est que, dans ma vision des choses, la bonne utilisation de
std::vector ou de tout autre container c'est avant tout d'écrire du code
qui rend explicite l'utilisation du container et d'éviter d'écrire des
boucles où l'on ne comprend pas facilement qui fait quoi et pourquoi.

Avatar
Loïc Joly
AG wrote:
J'ai une classe RandInt qui me permet de générer un vecteur "n"
d'unsigned int tiré "aléatoirement"

Je veux ensuite transformer ce vecteur en vecteur de doubles "d" compris
entre 0 et 1, en divisant mon vecteur "n" par la plus grand valeur
d'unsigned int possible (appelons là RandIntMax)

je suis bien obligé de faire quelque chose du genre :

std::vector<unsigned int> n(20);
std::vector<double> d(20);
unsigned int RandIntMax;


Si je passait en mode chipotage, je dirais que si le premier vecteur a
bien 20 éléments, le second lui ne doit pas être initialisé à 20, mais à
la taille du premier...

--
Loïc

Avatar
AG
Olivier Azeau wrote:
AG wrote:

J'ai une classe RandInt qui me permet de générer un vecteur "n"
d'unsigned int tiré "aléatoirement"

Je veux ensuite transformer ce vecteur en vecteur de doubles "d"
compris entre 0 et 1, en divisant mon vecteur "n" par la plus grand
valeur d'unsigned int possible (appelons là RandIntMax)

je suis bien obligé de faire quelque chose du genre :

std::vector<unsigned int> n(20);
std::vector<double> d(20);
unsigned int RandIntMax;



J'ai probablement mal formulé mon interrogation.
Ce qui me gêne dans de tels exemples c'est que l'intention du
programmeur n'est pas lisible.

Si dans le contexte de l'application les "unsigned int" vont toujours de
paire avec les "double", c'est à dire une relation 1-1 (quand on change
la valeur des int, on change celle des double), alors
std::vector<RandValue> me parait, en première approche, plus approprié
car une classe regroupant une paire de valeurs int et double va
permettre de mieux mettre en évidence les opérations réalisées sur ces
valeurs.
Ok, je comprends ça.



Si on a une relation 1-n (le même vecteur d'unsigned int sert
successivement à créer divers vecteurs de double) alors on ne peut que
garder les 2 vecteurs séparés mais dans un tel cas ils n'appartiennent
plus à la même classe car il y a création d'un vecteur à partir de
l'autre (et dans un tel cas je ne comprends pas pourquoi on
initialiserait le vecteur de double *avant* le calcul de la division par
RandIntMax)
effectivement, l'initialisation n'a pas lieu d'être avant le calcul de

la division dans mon cas précis.


Et il y a probablement d'autre cas, mais tout ce que j'essaie de dire
c'est que, dans ma vision des choses, la bonne utilisation de
std::vector ou de tout autre container c'est avant tout d'écrire du code
qui rend explicite l'utilisation du container et d'éviter d'écrire des
boucles où l'on ne comprend pas facilement qui fait quoi et pourquoi.
Je vais essayer, mais il me faudra probablement un peu de temps.


Merci pour ces clarifications.


Avatar
AG
Loïc Joly wrote:

AG wrote:

J'ai une classe RandInt qui me permet de générer un vecteur "n"
d'unsigned int tiré "aléatoirement"

Je veux ensuite transformer ce vecteur en vecteur de doubles "d"
compris entre 0 et 1, en divisant mon vecteur "n" par la plus grand
valeur d'unsigned int possible (appelons là RandIntMax)

je suis bien obligé de faire quelque chose du genre :

std::vector<unsigned int> n(20);
std::vector<double> d(20);
unsigned int RandIntMax;



Si je passait en mode chipotage, je dirais que si le premier vecteur a
bien 20 éléments, le second lui ne doit pas être initialisé à 20, mais à
la taille du premier...

Oui.



Avatar
AG
Alexandre wrote:

std::generate(bits.begin(),bits.end(),BitGen::GetBit);



bitgen.cpp(17) : error C2664: 'generate' : cannot convert parameter 3 from
'int (void)' to 'int (__thiscall *)(void)'
None of the functions with this name in scope match the target
type



à priori c'est parce que tu passes l'adresse d'une fonction membre, or à
priori l'algo generate ne peut pas y accéder (il n'a pas le this qui serait
utile pour, grosso modo...).
1ère solution : faire une fonction hors de toute classe comme prédicat
(bof...)
2e solution : ecrire un foncteur (un objet-fonction) cad une classe
possédant l'operator () (operator() ) prenant, dans ton cas, un int (si ton
vector bits contient un int). Et tu passes une instance de cet objet à
generate.


Oui, c'est ce que j'ai fini par comprendre. D'après mon livre, la
solution viendrait de la fonction mem_fun(). Elle ferait automatiquement
la deuxième solution.

AG.


Avatar
Fabien LE LEZ
On Thu, 10 Feb 2005 14:50:43 +0100, "Alexandre"
:

mais non, personne ne met jamais 20, voyons ;-)


Loi de Murphy : le simple fait de considérer dans un programme que
personne ne met jamais 20/20, garantit qu'une telle note sera
attribuée peu après la livraison définitive du logiciel.

--
;-)

Avatar
James Kanze
Loïc Joly wrote:
AG wrote:


J'ai une classe RandInt qui me permet de générer un vecteur
"n" d'unsigned int tiré "aléatoirement"



Je veux ensuite transformer ce vecteur en vecteur de doubles
"d" compris entre 0 et 1, en divisant mon vecteur "n" par la
plus grand valeur d'unsigned int possible (appelons là
RandIntMax)



je suis bien obligé de faire quelque chose du genre :



std::vector<unsigned int> n(20);
std::vector<double> d(20);
unsigned int RandIntMax;



Si je passait en mode chipotage, je dirais que si le premier
vecteur a bien 20 éléments, le second lui ne doit pas être
initialisé à 20, mais à la taille du premier...


Je crois que vous faîtes tous pas mal de suppositions sur son
application. Je trouve que son exemple de la ventilation des
notes n'était pas mal trouvé, et que dans ce cas-là, on
construira bien tous les vecteurs avec maxNote éléments. Il n'y
a pas, à première vue, un vecteur qui doit déterminer la taille
des autres.

--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


Avatar
korchkidu
Olivier Azeau wrote:


Là je ne comprends pas. Tu dis toi même "une animation est un vector
d'ensemble d'articulation" ce qui laisse supposer une classe "animation"
comme bon début de design, puis "je dois gerer 2 animations en
paralleles", ce qui laisse supposer 2 instances de cette classe.
Vu de cette facon, je pourrais etre d'accord avec toi...mais...


Ce qui me chiffonne c'est le "et seulement 2".
Cela signifie-t-il que ton argument est l'absence de besoin de
réutilisabilité ? (i.e. pas besoin de faire une classe pour un truc que
je n'utilise que 2 fois)
Si tel est le cas, j'apprécie : la reutilisabilité prématurée n'est pas
un bon critère de design pour moi non plus.
C'est plutot ca en effet qui retient mon attention.


Mais dans le cas présent, mon argument c'est la lisibilité.
Disons que personnellement (et je dis bien personnellement), je trouve

plus facile a comprendre de voir 2 std::vector contenant les objets qui
vont bien que 2 objets contenant les std::vector qui contiennent les
objets qui vont bien...uniquement dans le cas ou bien sur, la
reutilisabilite (pfiou, il est long ce mot...) est quasi nulle (voire
nulle).

K.

1 2 3 4 5