C'est marrant comme quoi des reflexes du C peuvent rester incrusté... Pour moi, end() dans une liste, c'est fondamentalement le pointeur NULL de toutes les listes chainées C.
Depuis quand est-ce qu'il y a un pointeur NULL dans une liste chaînée en C. J'ai toujours utilisé des listes doublement chaînées (qui permettent de supprimer un élément en ne connaissant que cet élément), avec une vertice « racine ». La fin de la liste avec la racine comme prochain élément, et le début comme élément précédant. Dans le cas d'une liste vide, la racine pointait à lui-même.
Itérer sur tous les éléments devenait :
for ( Node* p = racine->next ; p != &racine, p = p->next ) ...
L'utilisation des NULL ne fait que compliquer le code en introduisant des tests supplémentaires.
Et à chaque fois, faut que je me raisonne en me disant "mais non, comment faire end()-1 avec NULL ?". Mais c'est *le* piège (1) ou je tombe systématiquement.
D'ailleurs, un rapide coup d'oeuil sur le code de la list de mon g++ me dit que end() retourne un "_M_node", que begin() retourne un "_M_node->_M_next", et la définition de _M_node semble perdue deux niveaux d'héritage au dessus... Pas tout clair pour moi. Ils font une liste circulaire ?
Je crois. Je crois qu'il font à peu près comme j'ai fait ci-dessus. J'ai l'impression que la seule différence entre leur code et ce que je faisais auparavent (depuis au moins vingt ans maintenant), c'est qu'ils allouent la racine dynamiquement, tandis que chez moi, elle était membre. (Le membre, en fait, c'était un « Node » qui ne contenait que des pointeurs. Les éléments était des Element qui dérivait de Node, et je me servais des casts dans la classe de liste pour passer d'un à l'autre.)
-- James Kanze GABI Software 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
Marc Boyer wrote:
Loïc Joly <loic.actarus.joly@wanadoo.fr> writes:
| > Est-il légal d'assigner la valeur NULL à un itérateur ?
| Souvent, l'équivalent moral de NULL pour un itérateur sur
| une collection "c" est c.end()
C'est marrant comme quoi des reflexes du C peuvent
rester incrusté...
Pour moi, end() dans une liste, c'est fondamentalement
le pointeur NULL de toutes les listes chainées C.
Depuis quand est-ce qu'il y a un pointeur NULL dans une liste
chaînée en C. J'ai toujours utilisé des listes doublement
chaînées (qui permettent de supprimer un élément en ne
connaissant que cet élément), avec une vertice « racine ». La
fin de la liste avec la racine comme prochain élément, et le
début comme élément précédant. Dans le cas d'une liste vide, la
racine pointait à lui-même.
Itérer sur tous les éléments devenait :
for ( Node* p = racine->next ; p != &racine, p = p->next ) ...
L'utilisation des NULL ne fait que compliquer le code en
introduisant des tests supplémentaires.
Et à chaque fois, faut que je me raisonne en me disant
"mais non, comment faire end()-1 avec NULL ?".
Mais c'est *le* piège (1) ou je tombe systématiquement.
D'ailleurs, un rapide coup d'oeuil sur le code de la list de
mon g++ me dit que end() retourne un "_M_node", que begin()
retourne un "_M_node->_M_next", et la définition de _M_node
semble perdue deux niveaux d'héritage au dessus... Pas tout
clair pour moi.
Ils font une liste circulaire ?
Je crois. Je crois qu'il font à peu près comme j'ai fait
ci-dessus. J'ai l'impression que la seule différence entre leur
code et ce que je faisais auparavent (depuis au moins vingt ans
maintenant), c'est qu'ils allouent la racine dynamiquement,
tandis que chez moi, elle était membre. (Le membre, en fait,
c'était un « Node » qui ne contenait que des pointeurs. Les
éléments était des Element qui dérivait de Node, et je me
servais des casts dans la classe de liste pour passer d'un à
l'autre.)
--
James Kanze GABI Software
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
C'est marrant comme quoi des reflexes du C peuvent rester incrusté... Pour moi, end() dans une liste, c'est fondamentalement le pointeur NULL de toutes les listes chainées C.
Depuis quand est-ce qu'il y a un pointeur NULL dans une liste chaînée en C. J'ai toujours utilisé des listes doublement chaînées (qui permettent de supprimer un élément en ne connaissant que cet élément), avec une vertice « racine ». La fin de la liste avec la racine comme prochain élément, et le début comme élément précédant. Dans le cas d'une liste vide, la racine pointait à lui-même.
Itérer sur tous les éléments devenait :
for ( Node* p = racine->next ; p != &racine, p = p->next ) ...
L'utilisation des NULL ne fait que compliquer le code en introduisant des tests supplémentaires.
Et à chaque fois, faut que je me raisonne en me disant "mais non, comment faire end()-1 avec NULL ?". Mais c'est *le* piège (1) ou je tombe systématiquement.
D'ailleurs, un rapide coup d'oeuil sur le code de la list de mon g++ me dit que end() retourne un "_M_node", que begin() retourne un "_M_node->_M_next", et la définition de _M_node semble perdue deux niveaux d'héritage au dessus... Pas tout clair pour moi. Ils font une liste circulaire ?
Je crois. Je crois qu'il font à peu près comme j'ai fait ci-dessus. J'ai l'impression que la seule différence entre leur code et ce que je faisais auparavent (depuis au moins vingt ans maintenant), c'est qu'ils allouent la racine dynamiquement, tandis que chez moi, elle était membre. (Le membre, en fait, c'était un « Node » qui ne contenait que des pointeurs. Les éléments était des Element qui dérivait de Node, et je me servais des casts dans la classe de liste pour passer d'un à l'autre.)
-- James Kanze GABI Software 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
kanze
korchkidu wrote:
Gabriel Dos Reis wrote:
Loïc Joly writes:
| > Est-il légal d'assigner la valeur NULL à un itérateur ?
| Souvent, l'équivalent moral de NULL pour un itérateur sur une | collection "c" est c.end()
Essai-le. Et demande-toi ce que bien signifie le résultat d'un l.end() précédant après une insertion ?
-- James Kanze GABI Software 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
Henri de Solages
Pourquoi ne pas placer ces itérateurs dans un vector ?
Je n'aime pas les vector car, quand on fait un erase, les iterateurs sur les élements suivants ne sont plus valides. J'aime bien qu'on fasse suivre le courrier quand on déménage.
-- Get rid of the final underscore of my address to use it.
Pourquoi ne pas placer ces itérateurs dans un vector ?
Je n'aime pas les vector car, quand on fait un erase, les iterateurs sur les élements
suivants ne sont plus valides. J'aime bien qu'on fasse suivre le courrier quand on déménage.
--
Get rid of the final underscore of my address to use it.
Pourquoi ne pas placer ces itérateurs dans un vector ?
Je n'aime pas les vector car, quand on fait un erase, les iterateurs sur les élements suivants ne sont plus valides. J'aime bien qu'on fasse suivre le courrier quand on déménage.
-- Get rid of the final underscore of my address to use it.
Henri de Solages
Je veux un tableau d'itérateurs sur des éléments d'une list.
Sinon, ce dont tu as besoin, c'est d'un délimiteur de fin, donc le end() de la liste me semble une bonne valeur interdite.
Mais si j'ajoute ensuite des éléments à ma liste, le end() de la list est-il tenu par la norme de garder une même valeur ?
-- Get rid of the final underscore of my address to use it.
Je veux un tableau d'itérateurs sur des éléments d'une list.
Sinon, ce dont tu as besoin, c'est d'un délimiteur de
fin, donc le end() de la liste me semble une bonne
valeur interdite.
Mais si j'ajoute ensuite des éléments à ma liste, le end() de la list est-il tenu par la
norme de garder une même valeur ?
--
Get rid of the final underscore of my address to use it.
En effet, compile sans rien dire avec mon g++ (gcc 3.3.5). Je suis étonné. En fait, si j'arrive à bien interpréter ce qui se passe d'après un coup d'oeil au code de list sur ma machine, il se passe qu'un itérateur est une classe dont le seul membre est un pointeur sur un _List_node_base qui est une classique cellule: PtrSuivant, PtrPrecedent, Valeur.
Hors, cette classe possède un constructeur qui prend en paramètre un pointeur sur un _List_node_base. Ce constructeur n'est pas "explicit" (ce qui me semble une erreur de conception de prime abord), donc, si je me plante pas, il introduit une conversion implicite de _List_node_base* en iterator. Et comme NULL est un _List_node_base*...
D'où deux questions: - pour les gens avec un GCC plus récent, est-ce que le pb existe encore ? - pour les experts, est-ce qu'il ne faut pas considérer l'absence d'explicit comme un bug à rapporter à l'équipe de GCC ?
Marc Boyer -- À vélo, prendre une rue à contre-sens est moins dangeureux que prendre un boulevard dans le sens légal. À qui la faute ?
Henri de Solages <solages@CICT.fr_> a écrit :
Je remarque cependant que ni c++ ni icpc (compilateur d'Intel) ne me jettent quand
j'affecte NULL à un itérateur.
Amusant: tu as un bout de code.
# include <iostream>
# include <string>
# include <list>
using namespace std ;
int main( int argc, char ** argv ) {
list< string >::const_iterator i_nombres = NULL ;
En effet, compile sans rien dire avec mon g++ (gcc 3.3.5).
Je suis étonné.
En fait, si j'arrive à bien interpréter ce qui se passe
d'après un coup d'oeil au code de list sur ma machine,
il se passe qu'un itérateur est une classe dont le seul
membre est un pointeur sur un _List_node_base qui est
une classique cellule: PtrSuivant, PtrPrecedent, Valeur.
Hors, cette classe possède un constructeur qui prend
en paramètre un pointeur sur un _List_node_base.
Ce constructeur n'est pas "explicit" (ce qui me semble
une erreur de conception de prime abord), donc, si je
me plante pas, il introduit une conversion implicite
de _List_node_base* en iterator. Et comme NULL est
un _List_node_base*...
D'où deux questions:
- pour les gens avec un GCC plus récent, est-ce que
le pb existe encore ?
- pour les experts, est-ce qu'il ne faut pas considérer
l'absence d'explicit comme un bug à rapporter à
l'équipe de GCC ?
Marc Boyer
--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?
En effet, compile sans rien dire avec mon g++ (gcc 3.3.5). Je suis étonné. En fait, si j'arrive à bien interpréter ce qui se passe d'après un coup d'oeil au code de list sur ma machine, il se passe qu'un itérateur est une classe dont le seul membre est un pointeur sur un _List_node_base qui est une classique cellule: PtrSuivant, PtrPrecedent, Valeur.
Hors, cette classe possède un constructeur qui prend en paramètre un pointeur sur un _List_node_base. Ce constructeur n'est pas "explicit" (ce qui me semble une erreur de conception de prime abord), donc, si je me plante pas, il introduit une conversion implicite de _List_node_base* en iterator. Et comme NULL est un _List_node_base*...
D'où deux questions: - pour les gens avec un GCC plus récent, est-ce que le pb existe encore ? - pour les experts, est-ce qu'il ne faut pas considérer l'absence d'explicit comme un bug à rapporter à l'équipe de GCC ?
Marc Boyer -- À vélo, prendre une rue à contre-sens est moins dangeureux que prendre un boulevard dans le sens légal. À qui la faute ?
Marc Boyer
Henri de Solages a écrit :
Je veux un tableau d'itérateurs sur des éléments d'une list.
Sinon, ce dont tu as besoin, c'est d'un délimiteur de fin, donc le end() de la liste me semble une bonne valeur interdite.
Mais si j'ajoute ensuite des éléments à ma liste, le end() de la list est-il tenu par la norme de garder une même valeur ?
Comme souligné par Gaby, c'est loin d'être sur. En fait, je ne sais pas, mais par expérience des questions de Gaby, je pense que la répons est non (bien sur, si la validité de mon code dépendait de ça, je ne me baserait pas que sur cette intution).
Marc Boyer -- À vélo, prendre une rue à contre-sens est moins dangeureux que prendre un boulevard dans le sens légal. À qui la faute ?
Henri de Solages <solages@CICT.fr_> a écrit :
Je veux un tableau d'itérateurs sur des éléments d'une list.
Sinon, ce dont tu as besoin, c'est d'un délimiteur de
fin, donc le end() de la liste me semble une bonne
valeur interdite.
Mais si j'ajoute ensuite des éléments à ma liste, le end() de la list est-il tenu par la
norme de garder une même valeur ?
Comme souligné par Gaby, c'est loin d'être sur.
En fait, je ne sais pas, mais par expérience des questions
de Gaby, je pense que la répons est non (bien sur,
si la validité de mon code dépendait de ça, je ne
me baserait pas que sur cette intution).
Marc Boyer
--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?
Je veux un tableau d'itérateurs sur des éléments d'une list.
Sinon, ce dont tu as besoin, c'est d'un délimiteur de fin, donc le end() de la liste me semble une bonne valeur interdite.
Mais si j'ajoute ensuite des éléments à ma liste, le end() de la list est-il tenu par la norme de garder une même valeur ?
Comme souligné par Gaby, c'est loin d'être sur. En fait, je ne sais pas, mais par expérience des questions de Gaby, je pense que la répons est non (bien sur, si la validité de mon code dépendait de ça, je ne me baserait pas que sur cette intution).
Marc Boyer -- À vélo, prendre une rue à contre-sens est moins dangeureux que prendre un boulevard dans le sens légal. À qui la faute ?
Marc Boyer
Le 08-09-2005, kanze a écrit :
Marc Boyer wrote:
Loïc Joly writes:
| > Est-il légal d'assigner la valeur NULL à un itérateur ?
| Souvent, l'équivalent moral de NULL pour un itérateur sur | une collection "c" est c.end()
C'est marrant comme quoi des reflexes du C peuvent rester incrusté... Pour moi, end() dans une liste, c'est fondamentalement le pointeur NULL de toutes les listes chainées C.
Depuis quand est-ce qu'il y a un pointeur NULL dans une liste chaînée en C.
A l'école ?
J'ai toujours utilisé des listes doublement chaînées (qui permettent de supprimer un élément en ne connaissant que cet élément), avec une vertice « racine ». La fin de la liste avec la racine comme prochain élément, et le début comme élément précédant. Dans le cas d'une liste vide, la racine pointait à lui-même.
OK
Itérer sur tous les éléments devenait :
for ( Node* p = racine->next ; p != &racine, p = p->next ) ...
L'utilisation des NULL ne fait que compliquer le code en introduisant des tests supplémentaires.
Oui.
Et à chaque fois, faut que je me raisonne en me disant "mais non, comment faire end()-1 avec NULL ?". Mais c'est *le* piège (1) ou je tombe systématiquement.
D'ailleurs, un rapide coup d'oeuil sur le code de la list de mon g++ me dit que end() retourne un "_M_node", que begin() retourne un "_M_node->_M_next", et la définition de _M_node semble perdue deux niveaux d'héritage au dessus... Pas tout clair pour moi. Ils font une liste circulaire ?
Je crois. Je crois qu'il font à peu près comme j'ai fait ci-dessus. J'ai l'impression que la seule différence entre leur code et ce que je faisais auparavent (depuis au moins vingt ans maintenant), c'est qu'ils allouent la racine dynamiquement,
Oui. La classe possède un champ _M_node, qui semble être cette racine (d'ailleurs, end() se contente de retourner _M_node et begin() retourne _M_node->next), et le constructeur fait _M_node= _M_get_node(); qui est un appel à l'allocateur.
tandis que chez moi, elle était membre. (Le membre, en fait, c'était un « Node » qui ne contenait que des pointeurs. Les éléments était des Element qui dérivait de Node, et je me servais des casts dans la classe de liste pour passer d'un à l'autre.)
Oui.
Marc Boyer -- À vélo, prendre une rue à contre-sens est moins dangeureux que prendre un boulevard dans le sens légal. À qui la faute ?
Le 08-09-2005, kanze <kanze@gabi-soft.fr> a écrit :
Marc Boyer wrote:
Loïc Joly <loic.actarus.joly@wanadoo.fr> writes:
| > Est-il légal d'assigner la valeur NULL à un itérateur ?
| Souvent, l'équivalent moral de NULL pour un itérateur sur
| une collection "c" est c.end()
C'est marrant comme quoi des reflexes du C peuvent
rester incrusté...
Pour moi, end() dans une liste, c'est fondamentalement
le pointeur NULL de toutes les listes chainées C.
Depuis quand est-ce qu'il y a un pointeur NULL dans une liste
chaînée en C.
A l'école ?
J'ai toujours utilisé des listes doublement
chaînées (qui permettent de supprimer un élément en ne
connaissant que cet élément), avec une vertice « racine ». La
fin de la liste avec la racine comme prochain élément, et le
début comme élément précédant. Dans le cas d'une liste vide, la
racine pointait à lui-même.
OK
Itérer sur tous les éléments devenait :
for ( Node* p = racine->next ; p != &racine, p = p->next ) ...
L'utilisation des NULL ne fait que compliquer le code en
introduisant des tests supplémentaires.
Oui.
Et à chaque fois, faut que je me raisonne en me disant
"mais non, comment faire end()-1 avec NULL ?".
Mais c'est *le* piège (1) ou je tombe systématiquement.
D'ailleurs, un rapide coup d'oeuil sur le code de la list de
mon g++ me dit que end() retourne un "_M_node", que begin()
retourne un "_M_node->_M_next", et la définition de _M_node
semble perdue deux niveaux d'héritage au dessus... Pas tout
clair pour moi.
Ils font une liste circulaire ?
Je crois. Je crois qu'il font à peu près comme j'ai fait
ci-dessus. J'ai l'impression que la seule différence entre leur
code et ce que je faisais auparavent (depuis au moins vingt ans
maintenant), c'est qu'ils allouent la racine dynamiquement,
Oui. La classe possède un champ _M_node, qui semble être
cette racine (d'ailleurs, end() se contente de retourner
_M_node et begin() retourne _M_node->next), et le constructeur
fait
_M_node= _M_get_node();
qui est un appel à l'allocateur.
tandis que chez moi, elle était membre. (Le membre, en fait,
c'était un « Node » qui ne contenait que des pointeurs. Les
éléments était des Element qui dérivait de Node, et je me
servais des casts dans la classe de liste pour passer d'un à
l'autre.)
Oui.
Marc Boyer
--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?
C'est marrant comme quoi des reflexes du C peuvent rester incrusté... Pour moi, end() dans une liste, c'est fondamentalement le pointeur NULL de toutes les listes chainées C.
Depuis quand est-ce qu'il y a un pointeur NULL dans une liste chaînée en C.
A l'école ?
J'ai toujours utilisé des listes doublement chaînées (qui permettent de supprimer un élément en ne connaissant que cet élément), avec une vertice « racine ». La fin de la liste avec la racine comme prochain élément, et le début comme élément précédant. Dans le cas d'une liste vide, la racine pointait à lui-même.
OK
Itérer sur tous les éléments devenait :
for ( Node* p = racine->next ; p != &racine, p = p->next ) ...
L'utilisation des NULL ne fait que compliquer le code en introduisant des tests supplémentaires.
Oui.
Et à chaque fois, faut que je me raisonne en me disant "mais non, comment faire end()-1 avec NULL ?". Mais c'est *le* piège (1) ou je tombe systématiquement.
D'ailleurs, un rapide coup d'oeuil sur le code de la list de mon g++ me dit que end() retourne un "_M_node", que begin() retourne un "_M_node->_M_next", et la définition de _M_node semble perdue deux niveaux d'héritage au dessus... Pas tout clair pour moi. Ils font une liste circulaire ?
Je crois. Je crois qu'il font à peu près comme j'ai fait ci-dessus. J'ai l'impression que la seule différence entre leur code et ce que je faisais auparavent (depuis au moins vingt ans maintenant), c'est qu'ils allouent la racine dynamiquement,
Oui. La classe possède un champ _M_node, qui semble être cette racine (d'ailleurs, end() se contente de retourner _M_node et begin() retourne _M_node->next), et le constructeur fait _M_node= _M_get_node(); qui est un appel à l'allocateur.
tandis que chez moi, elle était membre. (Le membre, en fait, c'était un « Node » qui ne contenait que des pointeurs. Les éléments était des Element qui dérivait de Node, et je me servais des casts dans la classe de liste pour passer d'un à l'autre.)
Oui.
Marc Boyer -- À vélo, prendre une rue à contre-sens est moins dangeureux que prendre un boulevard dans le sens légal. À qui la faute ?
Stan
"Henri de Solages" a écrit dans le message de news: dfospn$2l5$
Pourquoi ne pas placer ces itérateurs dans un vector ?
Je n'aime pas les vector car, quand on fait un erase, les iterateurs sur les élements suivants ne sont plus valides. J'aime bien qu'on fasse suivre le courrier quand on déménage.
Il était question de parcourir :
Pour parcourir mes tableaux de pointeurs facilement
Après, tout dépend des besoins réels, peut être qu'un set pourait être une solution aussi.
-- -Stan
"Henri de Solages" <solages@CICT.fr_> a écrit dans le message de news:
dfospn$2l5$1@news.cict.fr...
Pourquoi ne pas placer ces itérateurs dans un vector ?
Je n'aime pas les vector car, quand on fait un erase, les iterateurs sur
les élements suivants ne sont plus valides. J'aime bien qu'on fasse suivre
le courrier quand on déménage.
Il était question de parcourir :
Pour parcourir mes tableaux de pointeurs facilement
Après, tout dépend des besoins réels, peut être qu'un set pourait
être une solution aussi.
"Henri de Solages" a écrit dans le message de news: dfospn$2l5$
Pourquoi ne pas placer ces itérateurs dans un vector ?
Je n'aime pas les vector car, quand on fait un erase, les iterateurs sur les élements suivants ne sont plus valides. J'aime bien qu'on fasse suivre le courrier quand on déménage.
Il était question de parcourir :
Pour parcourir mes tableaux de pointeurs facilement
Après, tout dépend des besoins réels, peut être qu'un set pourait être une solution aussi.
-- -Stan
Henri de Solages
Si tu as un tableau, pourquoi voudrais-tu le terminer par par NULL ? Connaître la taille du tableau ne suffit pas pour savoir quand s'arrêter ?
C'est bien ce que je pensais faire pour le cas avéré où l'on n'a pas le droit d'utiliser NULL, mais c'est plus lourd : quand je passe le tableau à une fonction, il faut aussi lui passer sa taille.
-- Get rid of the final underscore of my address to use it.
Si tu as un tableau, pourquoi voudrais-tu le terminer par par NULL ?
Connaître la taille du tableau ne suffit pas pour savoir quand
s'arrêter ?
C'est bien ce que je pensais faire pour le cas avéré où l'on n'a pas le droit d'utiliser NULL,
mais c'est plus lourd : quand je passe le tableau à une fonction, il faut aussi lui passer
sa taille.
--
Get rid of the final underscore of my address to use it.
Si tu as un tableau, pourquoi voudrais-tu le terminer par par NULL ? Connaître la taille du tableau ne suffit pas pour savoir quand s'arrêter ?
C'est bien ce que je pensais faire pour le cas avéré où l'on n'a pas le droit d'utiliser NULL, mais c'est plus lourd : quand je passe le tableau à une fonction, il faut aussi lui passer sa taille.
-- Get rid of the final underscore of my address to use it.