implementer un iterateur de X sur un std::vector< std::vector >
31 réponses
meow
Tout est dit dans le titre.
Pour faire court j'ai une classe qui contient un vector< vector X >
(o=F9 X est une classe) et j'aimerai it=E9rer sur tous les X contenus
dans ce vecteur de vecteurs. Je m'interroge donc sur la meilleure
fa=E7on de faire. J'imagine que la probl=E9matique est classique mais je
n'ai rien trouv=E9 sur le sujet.
On m'a souffl=E9 une solution facile : ma classe it=E9rateur contiendrait
un vector< X >, mise =E0 plat du vector<vector<X>> ainsi qu'un
it=E9rateur sur ce vecteur (appellons le it).
Je d=E9finirais alors mes op=E9rateurs ++, * et Cie simplement en les
d=E9l=E9guants =E0 it (i.e le ++ de mon it=E9rator fait juste un ++it, et
le * renvoie *it).
Cette solution me parrait lourdingue : si les vector<X> contiennent
beaucoup de X, mon it=E9rateur va bouffer beaucoup de m=E9moire. En
outre, contrairement aux it=E9rateurs de la stl, si ma structure tombe,
mon it=E9rateur continue =E0 etre valide (est-ce important ? Je suppose
que =E7a l'est si je veux faire des delete, replace, remove etc... mais
sinon ?) J'ai donc pens=E9 =E0 une autre solution :
dans mon_iterateur je stockerais un tableaux de paires d'it=E9rateurs
sur X. Chaque paire =E9tant constitu=E9e d'un it=E9rateur sur le d=E9but et
d'un it=E9rateur sur la fin d'un =E9l=E9ment de mon vector<vector<X>>.
J'aurai en outre encore un it=E9rateur sur mon vecteur de paire.
en gros :
class mon_iterateur {
vector<pair<vector<X>::iterator,vector<X>::iterator>> ;
vector<pair<vector<X>::iterator,vector<X>::iterator>> it;
.=2E.
mon_iterateur& operator++ {
if ((*it).first =3D=3D (*it).second) ++it else ++(*it);
return *this;
}
.=2E.
};
for (ConstIterVV<int> i; i != ConstIterVV<int>(); ++i) C'est ce que j'avais cru comprendre, mais ce qui me dérange dans cette
écriture, c'est le fait que le begin se réfère bien à une structure (celle sur laquelle on itère), alors que ce n'est pas le cas du end().
Ça, c'est pas bien méchant. D'ailleurs, istream_iterator<> fait pareil. Comme l'a dit James, tu peux créer des fonctions "begin" et "end" qui prennent chacun le vector<> en paramètre, même si la seconde ne l'utilise pas.
En lisant ce que vous avez écrit je me rends compte que finalement mon problème est plus profond et que pour commencer je ne sais pas trop bien ce qu'on appelle "itérateur". [...]et il ne démord pas du fait que c'est là ce qu'on appelle *itérateur*.
Le problème de fond, c'est que chacun a sa propre définition d'un itérateur.
Généralement, en C++, quand on parle d'"itérateur" sans autre précision, ça signifie "itérateur façon STL". Ce n'est vraisemblablement pas la notion d'itérateur la meilleure, mais c'est la plus connue, et la seule incluse dans le standard.
De plus, si on me demande d'ajouter à std:vector<...> un nouveau type d'itérateur, comme tu l'as demandé, j'ai tendance à utiliser le même type d'itérateurs que vector<>.
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Les itérateurs de la STL sont la généralisation de la notion de pointeur. En d'autres termes, un pointeur est un itérateur à part entière.
D'ailleurs, dans certaines (vieilles) implémentations de la STL, un std::vector<T>::iterator est en fait un T*. Ce n'est pas absolument conforme, mais en pratique, ça fonctionne.
On 15 Jan 2007 01:35:27 -0800, "meow" <schwarz.ben@gmail.com>:
for (ConstIterVV<int> i; i != ConstIterVV<int>(); ++i)
C'est ce que j'avais cru comprendre, mais ce qui me dérange dans cette
écriture, c'est le fait que le begin se réfère bien à une structure
(celle sur laquelle on itère), alors que ce n'est pas le cas du end().
Ça, c'est pas bien méchant. D'ailleurs, istream_iterator<> fait
pareil.
Comme l'a dit James, tu peux créer des fonctions "begin" et "end" qui
prennent chacun le vector<> en paramètre, même si la seconde ne
l'utilise pas.
En lisant ce que vous avez écrit je me rends compte que finalement mon
problème est plus profond et que pour commencer je ne sais pas trop
bien ce qu'on appelle "itérateur".
[...]et il ne démord pas du fait que c'est
là ce qu'on appelle *itérateur*.
Le problème de fond, c'est que chacun a sa propre définition d'un
itérateur.
Généralement, en C++, quand on parle d'"itérateur" sans autre
précision, ça signifie "itérateur façon STL".
Ce n'est vraisemblablement pas la notion d'itérateur la meilleure,
mais c'est la plus connue, et la seule incluse dans le standard.
De plus, si on me demande d'ajouter à std:vector<...> un nouveau type
d'itérateur, comme tu l'as demandé, j'ai tendance à utiliser le même
type d'itérateurs que vector<>.
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à
proprement parler des itérateurs ?!
Les itérateurs de la STL sont la généralisation de la notion de
pointeur. En d'autres termes, un pointeur est un itérateur à part
entière.
D'ailleurs, dans certaines (vieilles) implémentations de la STL, un
std::vector<T>::iterator est en fait un T*.
Ce n'est pas absolument conforme, mais en pratique, ça fonctionne.
for (ConstIterVV<int> i; i != ConstIterVV<int>(); ++i) C'est ce que j'avais cru comprendre, mais ce qui me dérange dans cette
écriture, c'est le fait que le begin se réfère bien à une structure (celle sur laquelle on itère), alors que ce n'est pas le cas du end().
Ça, c'est pas bien méchant. D'ailleurs, istream_iterator<> fait pareil. Comme l'a dit James, tu peux créer des fonctions "begin" et "end" qui prennent chacun le vector<> en paramètre, même si la seconde ne l'utilise pas.
En lisant ce que vous avez écrit je me rends compte que finalement mon problème est plus profond et que pour commencer je ne sais pas trop bien ce qu'on appelle "itérateur". [...]et il ne démord pas du fait que c'est là ce qu'on appelle *itérateur*.
Le problème de fond, c'est que chacun a sa propre définition d'un itérateur.
Généralement, en C++, quand on parle d'"itérateur" sans autre précision, ça signifie "itérateur façon STL". Ce n'est vraisemblablement pas la notion d'itérateur la meilleure, mais c'est la plus connue, et la seule incluse dans le standard.
De plus, si on me demande d'ajouter à std:vector<...> un nouveau type d'itérateur, comme tu l'as demandé, j'ai tendance à utiliser le même type d'itérateurs que vector<>.
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Les itérateurs de la STL sont la généralisation de la notion de pointeur. En d'autres termes, un pointeur est un itérateur à part entière.
D'ailleurs, dans certaines (vieilles) implémentations de la STL, un std::vector<T>::iterator est en fait un T*. Ce n'est pas absolument conforme, mais en pratique, ça fonctionne.
Fabien LE LEZ
On 15 Jan 2007 01:35:27 -0800, "meow" :
En fait, je pense au cas où ton VV est masqué à l'intérieur d'une classe (disons A), et que tu demandes tes itérateurs par a.begin() et a.end() (avec a, instance de A). Ta condition d'arret en intérrant sur a fonctionnerait tout aussi bien avec b.end()
Si je ne m'abuse, le code suivant a un comportement indéfini :
typedef ... Tableau; // vector<int> par exemple Tableau t1, t2; // remplissage
for (Tableau::const_iterator i= t1.begin(); i!=t2.end(); ++i) { ... }
L'expression "comportement indéfini" est claire : on ne peut pas prévoir ce que ça va faire. Ça peut donner quelque chose de bon les nuits de pleine lune uniquement, ou fonctionner parfaitement tout le temps, sauf avec une version précise de g++, etc.
Avec "typedef ConstIterVV<int> Tableau", ça fonctionne tout le temps. C'est pas bien méchant ; de toutes façons, le code n'a pas de sens.
On 15 Jan 2007 01:35:27 -0800, "meow" <schwarz.ben@gmail.com>:
En fait, je pense au cas où ton VV est masqué à l'intérieur d'une
classe (disons A), et que tu demandes tes itérateurs par a.begin() et
a.end() (avec a, instance de A). Ta condition d'arret en intérrant sur
a fonctionnerait tout aussi bien avec b.end()
Si je ne m'abuse, le code suivant a un comportement indéfini :
typedef ... Tableau; // vector<int> par exemple
Tableau t1, t2;
// remplissage
for (Tableau::const_iterator i= t1.begin(); i!=t2.end(); ++i)
{ ... }
L'expression "comportement indéfini" est claire : on ne peut pas
prévoir ce que ça va faire. Ça peut donner quelque chose de bon les
nuits de pleine lune uniquement, ou fonctionner parfaitement tout le
temps, sauf avec une version précise de g++, etc.
Avec "typedef ConstIterVV<int> Tableau", ça fonctionne tout le temps.
C'est pas bien méchant ; de toutes façons, le code n'a pas de sens.
En fait, je pense au cas où ton VV est masqué à l'intérieur d'une classe (disons A), et que tu demandes tes itérateurs par a.begin() et a.end() (avec a, instance de A). Ta condition d'arret en intérrant sur a fonctionnerait tout aussi bien avec b.end()
Si je ne m'abuse, le code suivant a un comportement indéfini :
typedef ... Tableau; // vector<int> par exemple Tableau t1, t2; // remplissage
for (Tableau::const_iterator i= t1.begin(); i!=t2.end(); ++i) { ... }
L'expression "comportement indéfini" est claire : on ne peut pas prévoir ce que ça va faire. Ça peut donner quelque chose de bon les nuits de pleine lune uniquement, ou fonctionner parfaitement tout le temps, sauf avec une version précise de g++, etc.
Avec "typedef ConstIterVV<int> Tableau", ça fonctionne tout le temps. C'est pas bien méchant ; de toutes façons, le code n'a pas de sens.
James Kanze
meow wrote:
@ Fabien LE LEZ
for (ConstIterVV<int> i; i != ConstIterVV<int>(); ++i) C'est ce que j'avais cru comprendre, mais ce qui me dérange dans cette
écriture, c'est le fait que le begin se réfère bien à une structu re (celle sur laquelle on itère), alors que ce n'est pas le cas du end(). En fait, je pense au cas où ton VV est masqué à l'intérieur d'une classe (disons A), et que tu demandes tes itérateurs par a.begin() et a.end() (avec a, instance de A). Ta condition d'arret en intérrant sur a fonctionnerait tout aussi bien avec b.end() (b autre instance de A). Pour "résoudre" ça, il suffirait d'inclure une condition sur l'adresse du vecteur pointé... Mais meme comme ça, ça me dérange, bien qu'honnètement je ne saurai dire pourquoi.
Si tu as une collection, rien n'empèche d'implémenter des fonctions begin() et end(), avec end() :
IterVV< T > CollectionVV< T >::end() { return IterVV< T >() ; }
Le client n'a besoin de savoir que end() ne se sert pas de la collection que s'il veut. De même avec mes fonctions globales : si j'appelle un algorithme standard, j'écris e.g. :
Quand je me sers de l'idiome STL, que m'importe les informations dont a besoin l'itérateur de fin.
@ Kanze & Fabien En lisant ce que vous avez écrit je me rends compte que finalement mon problème est plus profond et que pour commencer je ne sais pas trop bien ce qu'on appelle "itérateur". La "solution" proposée par Kanze avec des fonctions has_next(), next(), value() m'a été proposée par un collègue qui fait du Java, et il ne démord pas du fait que c'est là ce qu'on appelle *itérateur*.
C'est effectivement ce qu'on a toujours appelé un itérateur. Voir par exemple dans les modèles de conception (le GoF).
Note que le Java ne le fait pas vraiment comme il faut non plus, parce qu'il utilise la même fonction pour avancer et pour déréférencer, deux opérations distinctes. C'est ce que faisait les collections dans la bibliothèque USL, et on s'est vite rendu compte des problèmes (moins genant que la nécessité de deux itérateurs, mais genant quand même).
Après cogitation, cette solution me semble plus séduisante, parce qu'elle colle pls évidemment à ce qu'on a envie d'appeller itérateur.
Tout à fait.
Donc -arretez moi si je me trompe- tout le tintouin à coup de "++" et de "*" aurait été proposé par les cerveaux de la STL dans le soucis de répondre à un autre type de problématique, connexe à celle des itérateurs, mais pas tout a fait avec le meme cahier des charges.
Ça, c'est une autre thème. Pour moi, il y a bien abus de surcharge. Mais ça se discute : utiliser ++ comme nom de fonction pour aller à l'élément suivant, et * pour accéder à l'élément courant, ça ne change rien de fondamental ; c'est juste la façon qu'on épelle les fonctions. Avoir besoin de deux objets pour déterminer la fin, en revanche, c'est franchement pénible.
A première vue ce que je vois comme différence majeure, c'est le fait qu'un itérateur (au sens java (faute de trouver un meilleur terme) )
Au sens classique.
est capable de dire quand il est arrivé au bout de sa structure (fonction has_next) et qu'il n'a pas besoin d'etre comparé à un autre itérateur pour ce faire; ce qui n'est pas le cas des itérateurs STL...
Tout à fait. Il y a deux grands problèmes avec l'idiome à deux itérateurs :
-- Certains itérateurs ont besoin de connaître la fin lors des incrémentations. L'exemple type, c'est un itérateur filtrant, c-à-d un itérateur qui ne s'arrête qu'aux certains éléments.
-- Quand une fonction renvoie une séquence, elle est obligée à renvoyer deux valeurs. Ce qu'on ne peut pas passer directement comme paramètre à une autre fonction. On ne peut donc pas facilement enchaîner les fonctions.
Quand à savoir en quoi le design de la stl necessitait ces modifications au paradigme d'itérateur, pour moi c'est encore flou. Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
meow wrote:
@ Fabien LE LEZ
for (ConstIterVV<int> i; i != ConstIterVV<int>(); ++i)
C'est ce que j'avais cru comprendre, mais ce qui me dérange dans cette
écriture, c'est le fait que le begin se réfère bien à une structu re
(celle sur laquelle on itère), alors que ce n'est pas le cas du end().
En fait, je pense au cas où ton VV est masqué à l'intérieur d'une
classe (disons A), et que tu demandes tes itérateurs par a.begin() et
a.end() (avec a, instance de A). Ta condition d'arret en intérrant sur
a fonctionnerait tout aussi bien avec b.end() (b autre instance de A).
Pour "résoudre" ça, il suffirait d'inclure une condition sur
l'adresse du vecteur pointé... Mais meme comme ça, ça me dérange,
bien qu'honnètement je ne saurai dire pourquoi.
Si tu as une collection, rien n'empèche d'implémenter des
fonctions begin() et end(), avec end() :
IterVV< T >
CollectionVV< T >::end()
{
return IterVV< T >() ;
}
Le client n'a besoin de savoir que end() ne se sert pas de la
collection que s'il veut. De même avec mes fonctions globales :
si j'appelle un algorithme standard, j'écris e.g. :
Quand je me sers de l'idiome STL, que m'importe les informations
dont a besoin l'itérateur de fin.
@ Kanze & Fabien
En lisant ce que vous avez écrit je me rends compte que finalement mon
problème est plus profond et que pour commencer je ne sais pas trop
bien ce qu'on appelle "itérateur". La "solution" proposée par Kanze
avec des fonctions has_next(), next(), value() m'a été proposée par
un collègue qui fait du Java, et il ne démord pas du fait que c'est
là ce qu'on appelle *itérateur*.
C'est effectivement ce qu'on a toujours appelé un itérateur.
Voir par exemple dans les modèles de conception (le GoF).
Note que le Java ne le fait pas vraiment comme il faut non plus,
parce qu'il utilise la même fonction pour avancer et pour
déréférencer, deux opérations distinctes. C'est ce que faisait
les collections dans la bibliothèque USL, et on s'est vite rendu
compte des problèmes (moins genant que la nécessité de deux
itérateurs, mais genant quand même).
Après cogitation, cette solution me semble plus séduisante, parce
qu'elle colle pls évidemment à ce qu'on a envie d'appeller
itérateur.
Tout à fait.
Donc -arretez moi si je me trompe- tout le tintouin à coup de "++" et
de "*" aurait été proposé par les cerveaux de la STL dans le soucis
de répondre à un autre type de problématique, connexe à celle des
itérateurs, mais pas tout a fait avec le meme cahier des charges.
Ça, c'est une autre thème. Pour moi, il y a bien abus de
surcharge. Mais ça se discute : utiliser ++ comme nom de
fonction pour aller à l'élément suivant, et * pour accéder à
l'élément courant, ça ne change rien de fondamental ; c'est
juste la façon qu'on épelle les fonctions. Avoir besoin de deux
objets pour déterminer la fin, en revanche, c'est franchement
pénible.
A
première vue ce que je vois comme différence majeure, c'est le fait
qu'un itérateur (au sens java (faute de trouver un meilleur terme) )
Au sens classique.
est capable de dire quand il est arrivé au bout de sa structure
(fonction has_next) et qu'il n'a pas besoin d'etre comparé à un autre
itérateur pour ce faire; ce qui n'est pas le cas des itérateurs
STL...
Tout à fait. Il y a deux grands problèmes avec l'idiome à deux
itérateurs :
-- Certains itérateurs ont besoin de connaître la fin lors des
incrémentations. L'exemple type, c'est un itérateur
filtrant, c-à-d un itérateur qui ne s'arrête qu'aux certains
éléments.
-- Quand une fonction renvoie une séquence, elle est obligée à
renvoyer deux valeurs. Ce qu'on ne peut pas passer
directement comme paramètre à une autre fonction. On ne peut
donc pas facilement enchaîner les fonctions.
Quand à savoir en quoi le design de la stl necessitait ces
modifications au paradigme d'itérateur, pour moi c'est encore flou.
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à
proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
for (ConstIterVV<int> i; i != ConstIterVV<int>(); ++i) C'est ce que j'avais cru comprendre, mais ce qui me dérange dans cette
écriture, c'est le fait que le begin se réfère bien à une structu re (celle sur laquelle on itère), alors que ce n'est pas le cas du end(). En fait, je pense au cas où ton VV est masqué à l'intérieur d'une classe (disons A), et que tu demandes tes itérateurs par a.begin() et a.end() (avec a, instance de A). Ta condition d'arret en intérrant sur a fonctionnerait tout aussi bien avec b.end() (b autre instance de A). Pour "résoudre" ça, il suffirait d'inclure une condition sur l'adresse du vecteur pointé... Mais meme comme ça, ça me dérange, bien qu'honnètement je ne saurai dire pourquoi.
Si tu as une collection, rien n'empèche d'implémenter des fonctions begin() et end(), avec end() :
IterVV< T > CollectionVV< T >::end() { return IterVV< T >() ; }
Le client n'a besoin de savoir que end() ne se sert pas de la collection que s'il veut. De même avec mes fonctions globales : si j'appelle un algorithme standard, j'écris e.g. :
Quand je me sers de l'idiome STL, que m'importe les informations dont a besoin l'itérateur de fin.
@ Kanze & Fabien En lisant ce que vous avez écrit je me rends compte que finalement mon problème est plus profond et que pour commencer je ne sais pas trop bien ce qu'on appelle "itérateur". La "solution" proposée par Kanze avec des fonctions has_next(), next(), value() m'a été proposée par un collègue qui fait du Java, et il ne démord pas du fait que c'est là ce qu'on appelle *itérateur*.
C'est effectivement ce qu'on a toujours appelé un itérateur. Voir par exemple dans les modèles de conception (le GoF).
Note que le Java ne le fait pas vraiment comme il faut non plus, parce qu'il utilise la même fonction pour avancer et pour déréférencer, deux opérations distinctes. C'est ce que faisait les collections dans la bibliothèque USL, et on s'est vite rendu compte des problèmes (moins genant que la nécessité de deux itérateurs, mais genant quand même).
Après cogitation, cette solution me semble plus séduisante, parce qu'elle colle pls évidemment à ce qu'on a envie d'appeller itérateur.
Tout à fait.
Donc -arretez moi si je me trompe- tout le tintouin à coup de "++" et de "*" aurait été proposé par les cerveaux de la STL dans le soucis de répondre à un autre type de problématique, connexe à celle des itérateurs, mais pas tout a fait avec le meme cahier des charges.
Ça, c'est une autre thème. Pour moi, il y a bien abus de surcharge. Mais ça se discute : utiliser ++ comme nom de fonction pour aller à l'élément suivant, et * pour accéder à l'élément courant, ça ne change rien de fondamental ; c'est juste la façon qu'on épelle les fonctions. Avoir besoin de deux objets pour déterminer la fin, en revanche, c'est franchement pénible.
A première vue ce que je vois comme différence majeure, c'est le fait qu'un itérateur (au sens java (faute de trouver un meilleur terme) )
Au sens classique.
est capable de dire quand il est arrivé au bout de sa structure (fonction has_next) et qu'il n'a pas besoin d'etre comparé à un autre itérateur pour ce faire; ce qui n'est pas le cas des itérateurs STL...
Tout à fait. Il y a deux grands problèmes avec l'idiome à deux itérateurs :
-- Certains itérateurs ont besoin de connaître la fin lors des incrémentations. L'exemple type, c'est un itérateur filtrant, c-à-d un itérateur qui ne s'arrête qu'aux certains éléments.
-- Quand une fonction renvoie une séquence, elle est obligée à renvoyer deux valeurs. Ce qu'on ne peut pas passer directement comme paramètre à une autre fonction. On ne peut donc pas facilement enchaîner les fonctions.
Quand à savoir en quoi le design de la stl necessitait ces modifications au paradigme d'itérateur, pour moi c'est encore flou. Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
James Kanze
Fabien LE LEZ wrote:
[...]
Le problème de fond, c'est que chacun a sa propre définition d'un itérateur.
Maintenant. Le concepte d'itérateur n'est pas vraiment récent, et il y avait bien une entente sur sa signification, au moins dans les langages OO et procéduraux. (Je ne m'avancerai pas sur la signification d'itérateur dans un langage fonctionnel.) Puis, arrive la STL, qui utilise le mot pour quelque chose complétement différent.
[...]
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Les itérateurs de la STL sont la généralisation de la notion de pointeur. En d'autres termes, un pointeur est un itérateur à part entière.
Seulement parce qu'on a changé la signification d'itérateur.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Fabien LE LEZ wrote:
[...]
Le problème de fond, c'est que chacun a sa propre définition d'un
itérateur.
Maintenant. Le concepte d'itérateur n'est pas vraiment récent,
et il y avait bien une entente sur sa signification, au moins
dans les langages OO et procéduraux. (Je ne m'avancerai pas sur
la signification d'itérateur dans un langage fonctionnel.) Puis,
arrive la STL, qui utilise le mot pour quelque chose
complétement différent.
[...]
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à
proprement parler des itérateurs ?!
Les itérateurs de la STL sont la généralisation de la notion de
pointeur. En d'autres termes, un pointeur est un itérateur à part
entière.
Seulement parce qu'on a changé la signification d'itérateur.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Le problème de fond, c'est que chacun a sa propre définition d'un itérateur.
Maintenant. Le concepte d'itérateur n'est pas vraiment récent, et il y avait bien une entente sur sa signification, au moins dans les langages OO et procéduraux. (Je ne m'avancerai pas sur la signification d'itérateur dans un langage fonctionnel.) Puis, arrive la STL, qui utilise le mot pour quelque chose complétement différent.
[...]
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Les itérateurs de la STL sont la généralisation de la notion de pointeur. En d'autres termes, un pointeur est un itérateur à part entière.
Seulement parce qu'on a changé la signification d'itérateur.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Fabien LE LEZ
On 15 Jan 2007 09:49:39 -0800, "James Kanze" :
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
Pour décrire les itérateurs de la STL, j'emploierais plutôt l'expression "pointeurs généralisés". Les pointeurs intelligents, c'est encore autre chose (des classes qui gèrent la durée de vie d'objets).
On 15 Jan 2007 09:49:39 -0800, "James Kanze" <james.kanze@gmail.com>:
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à
proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
Pour décrire les itérateurs de la STL, j'emploierais plutôt
l'expression "pointeurs généralisés". Les pointeurs intelligents,
c'est encore autre chose (des classes qui gèrent la durée de vie
d'objets).
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
Pour décrire les itérateurs de la STL, j'emploierais plutôt l'expression "pointeurs généralisés". Les pointeurs intelligents, c'est encore autre chose (des classes qui gèrent la durée de vie d'objets).
James Kanze
Fabien LE LEZ wrote:
On 15 Jan 2007 09:49:39 -0800, "James Kanze" :
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
Pour décrire les itérateurs de la STL, j'emploierais plutôt l'expression "pointeurs généralisés". Les pointeurs intelligents, c'est encore autre chose (des classes qui gèrent la durée de vie d'objets).
Un pointeur intelligent ne gèrent pas forcément la durée de vie d'un objet ; ce n'en est qu'une des utilisations. En revanche, en effet, je préfère bien « pointeur généralisé » dans ce cas-ci. Parce que l'intelligence, je ne l'y vois pas.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Fabien LE LEZ wrote:
On 15 Jan 2007 09:49:39 -0800, "James Kanze" <james.kanze@gmail.com>:
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à
proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
Pour décrire les itérateurs de la STL, j'emploierais plutôt
l'expression "pointeurs généralisés". Les pointeurs intelligents,
c'est encore autre chose (des classes qui gèrent la durée de vie
d'objets).
Un pointeur intelligent ne gèrent pas forcément la durée de vie
d'un objet ; ce n'en est qu'une des utilisations. En revanche,
en effet, je préfère bien « pointeur généralisé » dans ce
cas-ci. Parce que l'intelligence, je ne l'y vois pas.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Bref, si je ne me trompe pas, les itérateurs sTL ne sont pas à proprement parler des itérateurs ?!
Pas vraiment. Ils se comportent plutôt des pointeurs intelligents.
Pour décrire les itérateurs de la STL, j'emploierais plutôt l'expression "pointeurs généralisés". Les pointeurs intelligents, c'est encore autre chose (des classes qui gèrent la durée de vie d'objets).
Un pointeur intelligent ne gèrent pas forcément la durée de vie d'un objet ; ce n'en est qu'une des utilisations. En revanche, en effet, je préfère bien « pointeur généralisé » dans ce cas-ci. Parce que l'intelligence, je ne l'y vois pas.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
meow
@Fabien
L'expression "comportement indéfini" est claire OK, je me range à ton argument... Cela dit, ce qui me chagrine
maintenant, c'est le fait qu'on puisse avoir des "comportements indéfinis" ;)
@James
Note que le Java ne le fait pas vraiment comme il faut non plus, parce qu'il utilise la même fonction pour avancer et pour déréférencer, deux opérations distinctes. C'est ce que faisait les collections dans la bibliothèque USL, et on s'est vite rendu compte des problèmes (moins genant que la nécessité de deux itérateurs, mais genant quand même). Juste pour etre certain : lorsque tu parles de la necessité de deux
itérateurs, tu fais bien référence à l'itérateur qu'on incrémente, et à celui qui pointe sur la fin et qu'on utilise pour comparer au premier ?
Merci encore à tous pour ces eclaircissements
@Fabien
L'expression "comportement indéfini" est claire
OK, je me range à ton argument... Cela dit, ce qui me chagrine
maintenant, c'est le fait qu'on puisse avoir des "comportements
indéfinis" ;)
@James
Note que le Java ne le fait pas vraiment comme il faut non plus,
parce qu'il utilise la même fonction pour avancer et pour
déréférencer, deux opérations distinctes. C'est ce que faisait
les collections dans la bibliothèque USL, et on s'est vite rendu
compte des problèmes (moins genant que la nécessité de deux
itérateurs, mais genant quand même).
Juste pour etre certain : lorsque tu parles de la necessité de deux
itérateurs, tu fais bien référence à l'itérateur qu'on
incrémente, et à celui qui pointe sur la fin et qu'on utilise pour
comparer au premier ?
L'expression "comportement indéfini" est claire OK, je me range à ton argument... Cela dit, ce qui me chagrine
maintenant, c'est le fait qu'on puisse avoir des "comportements indéfinis" ;)
@James
Note que le Java ne le fait pas vraiment comme il faut non plus, parce qu'il utilise la même fonction pour avancer et pour déréférencer, deux opérations distinctes. C'est ce que faisait les collections dans la bibliothèque USL, et on s'est vite rendu compte des problèmes (moins genant que la nécessité de deux itérateurs, mais genant quand même). Juste pour etre certain : lorsque tu parles de la necessité de deux
itérateurs, tu fais bien référence à l'itérateur qu'on incrémente, et à celui qui pointe sur la fin et qu'on utilise pour comparer au premier ?
Merci encore à tous pour ces eclaircissements
Fabien LE LEZ
On 17 Jan 2007 01:24:20 -0800, "meow" :
Cela dit, ce qui me chagrine maintenant, c'est le fait qu'on puisse avoir des "comportements indéfinis"
Malheureusement, il y en a pas mal en C++.
Juste pour etre certain : lorsque tu parles de la necessité de deux itérateurs, tu fais bien référence à l'itérateur qu'on incrémente, et à celui qui pointe sur la fin et qu'on utilise pour comparer au premier ?
Entre autres.
Si tu veux trier les éléments d'un vector<>, tu écriras :
std::sort (v.begin(), v.end());
Il n'y a pas vraiment là de notion d'incrémentation (du moins, pas visible), mais on a tout de même deux itérateurs.
On se retrouve à écrire quelque chose comme "... v.begin(), v.end() ..." toutes les cinq minutes.
On 17 Jan 2007 01:24:20 -0800, "meow" <schwarz.ben@gmail.com>:
Cela dit, ce qui me chagrine
maintenant, c'est le fait qu'on puisse avoir des "comportements
indéfinis"
Malheureusement, il y en a pas mal en C++.
Juste pour etre certain : lorsque tu parles de la necessité de deux
itérateurs, tu fais bien référence à l'itérateur qu'on
incrémente, et à celui qui pointe sur la fin et qu'on utilise pour
comparer au premier ?
Entre autres.
Si tu veux trier les éléments d'un vector<>, tu écriras :
std::sort (v.begin(), v.end());
Il n'y a pas vraiment là de notion d'incrémentation (du moins, pas
visible), mais on a tout de même deux itérateurs.
On se retrouve à écrire quelque chose comme
"... v.begin(), v.end() ..." toutes les cinq minutes.
Cela dit, ce qui me chagrine maintenant, c'est le fait qu'on puisse avoir des "comportements indéfinis"
Malheureusement, il y en a pas mal en C++.
Juste pour etre certain : lorsque tu parles de la necessité de deux itérateurs, tu fais bien référence à l'itérateur qu'on incrémente, et à celui qui pointe sur la fin et qu'on utilise pour comparer au premier ?
Entre autres.
Si tu veux trier les éléments d'un vector<>, tu écriras :
std::sort (v.begin(), v.end());
Il n'y a pas vraiment là de notion d'incrémentation (du moins, pas visible), mais on a tout de même deux itérateurs.
On se retrouve à écrire quelque chose comme "... v.begin(), v.end() ..." toutes les cinq minutes.
Marc Boyer
Le 17-01-2007, meow a écrit :
@Fabien
L'expression "comportement indéfini" est claire OK, je me range à ton argument... Cela dit, ce qui me chagrine
maintenant, c'est le fait qu'on puisse avoir des "comportements indéfinis" ;)
Ne pas vouloir de "comportement indéfini", c'est être prêt à payer le surcoût de vérifications systématiques. Ceci dit, rien dans la norme n'empèche donc un compilo de spécialiser "comportement indéfini" en quelque chose de défini. Est-ce qu'il y a un marché pour un tel compilo ? Je ne sais pas répondre.
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
Le 17-01-2007, meow <schwarz.ben@gmail.com> a écrit :
@Fabien
L'expression "comportement indéfini" est claire
OK, je me range à ton argument... Cela dit, ce qui me chagrine
maintenant, c'est le fait qu'on puisse avoir des "comportements
indéfinis" ;)
Ne pas vouloir de "comportement indéfini", c'est être prêt
à payer le surcoût de vérifications systématiques.
Ceci dit, rien dans la norme n'empèche donc un compilo
de spécialiser "comportement indéfini" en quelque chose de
défini. Est-ce qu'il y a un marché pour un tel compilo ?
Je ne sais pas répondre.
Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)
L'expression "comportement indéfini" est claire OK, je me range à ton argument... Cela dit, ce qui me chagrine
maintenant, c'est le fait qu'on puisse avoir des "comportements indéfinis" ;)
Ne pas vouloir de "comportement indéfini", c'est être prêt à payer le surcoût de vérifications systématiques. Ceci dit, rien dans la norme n'empèche donc un compilo de spécialiser "comportement indéfini" en quelque chose de défini. Est-ce qu'il y a un marché pour un tel compilo ? Je ne sais pas répondre.
Marc Boyer -- Si tu peux supporter d'entendre tes paroles Travesties par des gueux pour exciter des sots IF -- Rudyard Kipling (Trad. André Maurois)
Fabien LE LEZ
On Wed, 17 Jan 2007 12:23:34 +0000 (UTC), Marc Boyer :
Ceci dit, rien dans la norme n'empèche donc un compilo de spécialiser "comportement indéfini" en quelque chose de défini.
Certes. Mais ça m'étonnerait qu'un éditeur de compilo soit capable de prévoir tous les cas.
Par contre, il est courant qu'un compilo ait un comportement défini dans certains cas.
Exemple :
std::vector<int> v; ++v[0];
Selon la norme, le comportement est indéfini. Sous VC++ en mode "release", idem. Sous VC++ en mode "debug", le comportement est parfaitement défini. Je ne m'en souviens plus, mais il me semble que c'est un abort().
On Wed, 17 Jan 2007 12:23:34 +0000 (UTC), Marc Boyer :
Ceci dit, rien dans la norme n'empèche donc un compilo
de spécialiser "comportement indéfini" en quelque chose de
défini.
Certes. Mais ça m'étonnerait qu'un éditeur de compilo soit capable de
prévoir tous les cas.
Par contre, il est courant qu'un compilo ait un comportement défini
dans certains cas.
Exemple :
std::vector<int> v;
++v[0];
Selon la norme, le comportement est indéfini.
Sous VC++ en mode "release", idem.
Sous VC++ en mode "debug", le comportement est parfaitement défini. Je
ne m'en souviens plus, mais il me semble que c'est un abort().
On Wed, 17 Jan 2007 12:23:34 +0000 (UTC), Marc Boyer :
Ceci dit, rien dans la norme n'empèche donc un compilo de spécialiser "comportement indéfini" en quelque chose de défini.
Certes. Mais ça m'étonnerait qu'un éditeur de compilo soit capable de prévoir tous les cas.
Par contre, il est courant qu'un compilo ait un comportement défini dans certains cas.
Exemple :
std::vector<int> v; ++v[0];
Selon la norme, le comportement est indéfini. Sous VC++ en mode "release", idem. Sous VC++ en mode "debug", le comportement est parfaitement défini. Je ne m'en souviens plus, mais il me semble que c'est un abort().