Marc Boyer writes:
| Henri de Solages a écrit :
| - pour les experts, est-ce qu'il ne faut pas considérer
| l'absence d'explicit comme un bug à rapporter à
| l'équipe de GCC ?
C'en est un. Peux-tu faire un bug report ? (mets moi en CC: du PR, mon
email chez GNU est gdr at gcc dot gnu dot org).
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
| Henri de Solages <solages@CICT.fr_> a écrit :
| - pour les experts, est-ce qu'il ne faut pas considérer
| l'absence d'explicit comme un bug à rapporter à
| l'équipe de GCC ?
C'en est un. Peux-tu faire un bug report ? (mets moi en CC: du PR, mon
email chez GNU est gdr at gcc dot gnu dot org).
Marc Boyer writes:
| Henri de Solages a écrit :
| - pour les experts, est-ce qu'il ne faut pas considérer
| l'absence d'explicit comme un bug à rapporter à
| l'équipe de GCC ?
C'en est un. Peux-tu faire un bug report ? (mets moi en CC: du PR, mon
email chez GNU est gdr at gcc dot gnu dot org).
Marc Boyer wrote:Depuis quand est-ce qu'il y a un pointeur NULL dans une
liste chaînée en C.
A l'école ?
Je sais que j'ai effectivement vu une telle technique dans des
livres. Mais que je n'ai jamais compris pourquoi -- la solution
avec la liste circulaire est tellement évidente, et bien plus
simple à coder ET plus rapide. Il ne m'est jamais venu à
l'ésprit d'en faire autrement.
Peut-être c'est parce que quand j'ai abordé les listes chaînées
pour la première fois, on avait déjà assez de mémoire pour ne
pas être obligé à s'emmerder avec des listes à chaînage simple,
or que les auteurs des livres ont commencé avec des listes à
chaînage simple (où je ne vois guère d'autre solution qu'une
valeur sentinelle comme NULL), et ont simplement continué pareil
avec des listes à chaînage double, même si une solution plus
simple existe.
Marc Boyer wrote:
Depuis quand est-ce qu'il y a un pointeur NULL dans une
liste chaînée en C.
A l'école ?
Je sais que j'ai effectivement vu une telle technique dans des
livres. Mais que je n'ai jamais compris pourquoi -- la solution
avec la liste circulaire est tellement évidente, et bien plus
simple à coder ET plus rapide. Il ne m'est jamais venu à
l'ésprit d'en faire autrement.
Peut-être c'est parce que quand j'ai abordé les listes chaînées
pour la première fois, on avait déjà assez de mémoire pour ne
pas être obligé à s'emmerder avec des listes à chaînage simple,
or que les auteurs des livres ont commencé avec des listes à
chaînage simple (où je ne vois guère d'autre solution qu'une
valeur sentinelle comme NULL), et ont simplement continué pareil
avec des listes à chaînage double, même si une solution plus
simple existe.
Marc Boyer wrote:Depuis quand est-ce qu'il y a un pointeur NULL dans une
liste chaînée en C.
A l'école ?
Je sais que j'ai effectivement vu une telle technique dans des
livres. Mais que je n'ai jamais compris pourquoi -- la solution
avec la liste circulaire est tellement évidente, et bien plus
simple à coder ET plus rapide. Il ne m'est jamais venu à
l'ésprit d'en faire autrement.
Peut-être c'est parce que quand j'ai abordé les listes chaînées
pour la première fois, on avait déjà assez de mémoire pour ne
pas être obligé à s'emmerder avec des listes à chaînage simple,
or que les auteurs des livres ont commencé avec des listes à
chaînage simple (où je ne vois guère d'autre solution qu'une
valeur sentinelle comme NULL), et ont simplement continué pareil
avec des listes à chaînage double, même si une solution plus
simple existe.
Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Je crois que ce qui serait difficile à faire comprendre à
des débutants, c'est que même dans une liste vide, on met un
élément, et que la valeur transportée par cet élément on ne
s'y intéresse pas.
Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Je crois que ce qui serait difficile à faire comprendre à
des débutants, c'est que même dans une liste vide, on met un
élément, et que la valeur transportée par cet élément on ne
s'y intéresse pas.
Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Je crois que ce qui serait difficile à faire comprendre à
des débutants, c'est que même dans une liste vide, on met un
élément, et que la valeur transportée par cet élément on ne
s'y intéresse pas.
Marc Boyer wrote:Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Je crois que ce qui serait difficile à faire comprendre à
des débutants, c'est que même dans une liste vide, on met un
élément, et que la valeur transportée par cet élément on ne
s'y intéresse pas.
Sauf que je n'y mets pas d'élément supplémentaire.
Mais évidemment, j'ai plein des cast, dans une classe générique.
Ce qui n'est peut-être pas ce qu'on veut montrer aux débuttants
non plus. Et que ça pourrait prêter à confusion que parfois mon
Node* est un Element*, et parfois (quand le Node est la racine)
non.
Marc Boyer wrote:
Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Je crois que ce qui serait difficile à faire comprendre à
des débutants, c'est que même dans une liste vide, on met un
élément, et que la valeur transportée par cet élément on ne
s'y intéresse pas.
Sauf que je n'y mets pas d'élément supplémentaire.
Mais évidemment, j'ai plein des cast, dans une classe générique.
Ce qui n'est peut-être pas ce qu'on veut montrer aux débuttants
non plus. Et que ça pourrait prêter à confusion que parfois mon
Node* est un Element*, et parfois (quand le Node est la racine)
non.
Marc Boyer wrote:Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Je crois que ce qui serait difficile à faire comprendre à
des débutants, c'est que même dans une liste vide, on met un
élément, et que la valeur transportée par cet élément on ne
s'y intéresse pas.
Sauf que je n'y mets pas d'élément supplémentaire.
Mais évidemment, j'ai plein des cast, dans une classe générique.
Ce qui n'est peut-être pas ce qu'on veut montrer aux débuttants
non plus. Et que ça pourrait prêter à confusion que parfois mon
Node* est un Element*, et parfois (quand le Node est la racine)
non.
Marc Boyer writes:
[...]
| > 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.
Non, il n'y a pas d'allocation dynamique de la racine.
| La classe possède un champ _M_node, qui semble être
struct _List_impl
: public _Node_Alloc_type
{
_List_node_base _M_node;
_List_impl (const _Node_Alloc_type& __a)
: _Node_Alloc_type(__a)
{ }
};
Cette racine n'est pas allouée dynamiquement.
| 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();
Le constructeur fait ceci :
_List_base(const allocator_type& __a)
: _M_impl(__a)
{ _M_init(); }
Et _M_init() est:
void
_M_init()
{
this->_M_impl._M_node._M_next = &this->_M_impl._M_node;
this->_M_impl._M_node._M_prev = &this->_M_impl._M_node;
}
Je ne vois toujours pas d'allocation dynamique.
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
[...]
| > 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.
Non, il n'y a pas d'allocation dynamique de la racine.
| La classe possède un champ _M_node, qui semble être
struct _List_impl
: public _Node_Alloc_type
{
_List_node_base _M_node;
_List_impl (const _Node_Alloc_type& __a)
: _Node_Alloc_type(__a)
{ }
};
Cette racine n'est pas allouée dynamiquement.
| 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();
Le constructeur fait ceci :
_List_base(const allocator_type& __a)
: _M_impl(__a)
{ _M_init(); }
Et _M_init() est:
void
_M_init()
{
this->_M_impl._M_node._M_next = &this->_M_impl._M_node;
this->_M_impl._M_node._M_prev = &this->_M_impl._M_node;
}
Je ne vois toujours pas d'allocation dynamique.
Marc Boyer writes:
[...]
| > 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.
Non, il n'y a pas d'allocation dynamique de la racine.
| La classe possède un champ _M_node, qui semble être
struct _List_impl
: public _Node_Alloc_type
{
_List_node_base _M_node;
_List_impl (const _Node_Alloc_type& __a)
: _Node_Alloc_type(__a)
{ }
};
Cette racine n'est pas allouée dynamiquement.
| 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();
Le constructeur fait ceci :
_List_base(const allocator_type& __a)
: _M_impl(__a)
{ _M_init(); }
Et _M_init() est:
void
_M_init()
{
this->_M_impl._M_node._M_next = &this->_M_impl._M_node;
this->_M_impl._M_node._M_prev = &this->_M_impl._M_node;
}
Je ne vois toujours pas d'allocation dynamique.
"kanze" writes:Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Ca depend du contexte, utiliser NULL peut etre utile si tu
dois parcourir la fin de la liste et que tu n'as pas acces au
noeud special pour t'en servir de sentinelle (par exemple si
ta liste est invasive).
"kanze" <kanze@gabi-soft.fr> writes:
Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Ca depend du contexte, utiliser NULL peut etre utile si tu
dois parcourir la fin de la liste et que tu n'as pas acces au
noeud special pour t'en servir de sentinelle (par exemple si
ta liste est invasive).
"kanze" writes:Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Ca depend du contexte, utiliser NULL peut etre utile si tu
dois parcourir la fin de la liste et que tu n'as pas acces au
noeud special pour t'en servir de sentinelle (par exemple si
ta liste est invasive).
Marc Boyer writes:
| Ils font une liste circulaire ?
En quelque sorte. Mais un noeud dans cette liste « circulaire » sert à
marquer end(), donc de l'extérieur ce n'est pas une liste circulaire.
Mais on peut expliquer pourquoi le code ci-dessus va boucler
indéfiniment (à condition que l.size() > 0) sans regarder une
implémentation particulière.
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
| Ils font une liste circulaire ?
En quelque sorte. Mais un noeud dans cette liste « circulaire » sert à
marquer end(), donc de l'extérieur ce n'est pas une liste circulaire.
Mais on peut expliquer pourquoi le code ci-dessus va boucler
indéfiniment (à condition que l.size() > 0) sans regarder une
implémentation particulière.
Marc Boyer writes:
| Ils font une liste circulaire ?
En quelque sorte. Mais un noeud dans cette liste « circulaire » sert à
marquer end(), donc de l'extérieur ce n'est pas une liste circulaire.
Mais on peut expliquer pourquoi le code ci-dessus va boucler
indéfiniment (à condition que l.size() > 0) sans regarder une
implémentation particulière.
Jean-Marc Bourguet wrote:"kanze" writes:Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Ca depend du contexte, utiliser NULL peut etre utile si tu
dois parcourir la fin de la liste et que tu n'as pas acces au
noeud special pour t'en servir de sentinelle (par exemple si
ta liste est invasive).
Et comment est-ce que tu trouves le debut de la liste, si tu ne
connais pas le noeud spécial ?
C'est surtout avec les listes invasives que j'aime cette
technique. Parce qu'il me permet d'enlever l'élément de la
liste dans son destructeur, sans que l'élément lui-même sache
dans quelle liste il se trouve. Genre :
Node::~Node()
{
next->prec = prec ;
prec->next = next ;
}
Jean-Marc Bourguet wrote:
"kanze" <kanze@gabi-soft.fr> writes:
Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Ca depend du contexte, utiliser NULL peut etre utile si tu
dois parcourir la fin de la liste et que tu n'as pas acces au
noeud special pour t'en servir de sentinelle (par exemple si
ta liste est invasive).
Et comment est-ce que tu trouves le debut de la liste, si tu ne
connais pas le noeud spécial ?
C'est surtout avec les listes invasives que j'aime cette
technique. Parce qu'il me permet d'enlever l'élément de la
liste dans son destructeur, sans que l'élément lui-même sache
dans quelle liste il se trouve. Genre :
Node::~Node()
{
next->prec = prec ;
prec->next = next ;
}
Jean-Marc Bourguet wrote:"kanze" writes:Peut-être c'est parce que quand j'ai abordé les listes
chaînées pour la première fois, on avait déjà assez de
mémoire pour ne pas être obligé à s'emmerder avec des listes
à chaînage simple, or que les auteurs des livres ont
commencé avec des listes à chaînage simple (où je ne vois
guère d'autre solution qu'une valeur sentinelle comme NULL),
et ont simplement continué pareil avec des listes à chaînage
double, même si une solution plus simple existe.
Ca depend du contexte, utiliser NULL peut etre utile si tu
dois parcourir la fin de la liste et que tu n'as pas acces au
noeud special pour t'en servir de sentinelle (par exemple si
ta liste est invasive).
Et comment est-ce que tu trouves le debut de la liste, si tu ne
connais pas le noeud spécial ?
C'est surtout avec les listes invasives que j'aime cette
technique. Parce qu'il me permet d'enlever l'élément de la
liste dans son destructeur, sans que l'élément lui-même sache
dans quelle liste il se trouve. Genre :
Node::~Node()
{
next->prec = prec ;
prec->next = next ;
}
Gabriel Dos Reis a écrit :Marc Boyer writes:
| Ils font une liste circulaire ?
En quelque sorte. Mais un noeud dans cette liste « circulaire » sert à
marquer end(), donc de l'extérieur ce n'est pas une liste circulaire.
Mais on peut expliquer pourquoi le code ci-dessus va boucler
indéfiniment (à condition que l.size() > 0) sans regarder une
implémentation particulière.
A condition de comprendre que end() est modifié par
le push_back(), c'est à dire que end() dépend du contenu
de la liste.
Et puis il y a cette connaissance que les itérateurs de
liste ne sont pas invalidés par les insertions. En
réflechissant 2mn, on réalise que begin() est fondamentalement
invalidé par un push_front(), donc, on peut se méfier du
fait que end() le soit de temps en temps.
Mais en fait, faudrait que je prenne un papier et un crayon
peut-être, mais je n'arrive pas à voir ce qui invalide end()
dans l'implémentation de liste quasi-circulaire dont nous parlons.
Gabriel Dos Reis <gdr@integrable-solutions.net> a écrit :
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
| Ils font une liste circulaire ?
En quelque sorte. Mais un noeud dans cette liste « circulaire » sert à
marquer end(), donc de l'extérieur ce n'est pas une liste circulaire.
Mais on peut expliquer pourquoi le code ci-dessus va boucler
indéfiniment (à condition que l.size() > 0) sans regarder une
implémentation particulière.
A condition de comprendre que end() est modifié par
le push_back(), c'est à dire que end() dépend du contenu
de la liste.
Et puis il y a cette connaissance que les itérateurs de
liste ne sont pas invalidés par les insertions. En
réflechissant 2mn, on réalise que begin() est fondamentalement
invalidé par un push_front(), donc, on peut se méfier du
fait que end() le soit de temps en temps.
Mais en fait, faudrait que je prenne un papier et un crayon
peut-être, mais je n'arrive pas à voir ce qui invalide end()
dans l'implémentation de liste quasi-circulaire dont nous parlons.
Gabriel Dos Reis a écrit :Marc Boyer writes:
| Ils font une liste circulaire ?
En quelque sorte. Mais un noeud dans cette liste « circulaire » sert à
marquer end(), donc de l'extérieur ce n'est pas une liste circulaire.
Mais on peut expliquer pourquoi le code ci-dessus va boucler
indéfiniment (à condition que l.size() > 0) sans regarder une
implémentation particulière.
A condition de comprendre que end() est modifié par
le push_back(), c'est à dire que end() dépend du contenu
de la liste.
Et puis il y a cette connaissance que les itérateurs de
liste ne sont pas invalidés par les insertions. En
réflechissant 2mn, on réalise que begin() est fondamentalement
invalidé par un push_front(), donc, on peut se méfier du
fait que end() le soit de temps en temps.
Mais en fait, faudrait que je prenne un papier et un crayon
peut-être, mais je n'arrive pas à voir ce qui invalide end()
dans l'implémentation de liste quasi-circulaire dont nous parlons.