Est ce que *first a un comportement defini si first vaut NULL ?
quelle importance puisqu'il N'est PAS déréférencé ...
Bien sur que si... petit rappel:
class A {
A& a;
A(A another) : a(another) { ... }
/*virtual*/ void execute() { ... }
void crash() {
a.execute();
}
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
J'ajoute que ce serait contre-productif
(une pessimisation). Il devient tout-à-coup nécessaire de tester
dans les fonctions membres l'adresse de la référence à coup de :
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
Sinon on utilise un pointeur, pas une référence. Faut pas mélanger
des concepts qui visent des buts différents.
Quand on se bat contre le compilateur, on est toujours perdant!
Mais quel est l'intérêt de faire ça ? Je n'en vois aucun.
Mes 2 centimes suisses,
Est ce que *first a un comportement defini si first vaut NULL ?
quelle importance puisqu'il N'est PAS déréférencé ...
Bien sur que si... petit rappel:
class A {
A& a;
A(A another) : a(another) { ... }
/*virtual*/ void execute() { ... }
void crash() {
a.execute();
}
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
J'ajoute que ce serait contre-productif
(une pessimisation). Il devient tout-à-coup nécessaire de tester
dans les fonctions membres l'adresse de la référence à coup de :
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
Sinon on utilise un pointeur, pas une référence. Faut pas mélanger
des concepts qui visent des buts différents.
Quand on se bat contre le compilateur, on est toujours perdant!
Mais quel est l'intérêt de faire ça ? Je n'en vois aucun.
Mes 2 centimes suisses,
Est ce que *first a un comportement defini si first vaut NULL ?
quelle importance puisqu'il N'est PAS déréférencé ...
Bien sur que si... petit rappel:
class A {
A& a;
A(A another) : a(another) { ... }
/*virtual*/ void execute() { ... }
void crash() {
a.execute();
}
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
J'ajoute que ce serait contre-productif
(une pessimisation). Il devient tout-à-coup nécessaire de tester
dans les fonctions membres l'adresse de la référence à coup de :
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
Sinon on utilise un pointeur, pas une référence. Faut pas mélanger
des concepts qui visent des buts différents.
Quand on se bat contre le compilateur, on est toujours perdant!
Mais quel est l'intérêt de faire ça ? Je n'en vois aucun.
Mes 2 centimes suisses,
qui s'autorisera à avoir des références nulles devra les tester
qui s'autorisera à avoir des références nulles devra les tester
qui s'autorisera à avoir des références nulles devra les tester
Sylvain schrieb:qui s'autorisera à avoir des références nulles devra les tester
On les teste comment, sachant que le compilateur a le droit d'éliminer
le test ? De plus, rien ne garantit que la référence reste nulle lorsque
l'héritage entre en jeu ! Question à 0,02 : Qu'affiche-t-il le
programme suivant :
Sylvain schrieb:
qui s'autorisera à avoir des références nulles devra les tester
On les teste comment, sachant que le compilateur a le droit d'éliminer
le test ? De plus, rien ne garantit que la référence reste nulle lorsque
l'héritage entre en jeu ! Question à 0,02 : Qu'affiche-t-il le
programme suivant :
Sylvain schrieb:qui s'autorisera à avoir des références nulles devra les tester
On les teste comment, sachant que le compilateur a le droit d'éliminer
le test ? De plus, rien ne garantit que la référence reste nulle lorsque
l'héritage entre en jeu ! Question à 0,02 : Qu'affiche-t-il le
programme suivant :
wrote:
S'il y a déréférencement dans ce cas-là, il y aura crash à
l'exécution. Je n'ai encore rencontré aucun compilateur qui
sacrifie la rapidité du code (génère une instruction de plus)
dans le but de provoquer un crash.
Il te manque de l'expérience, alors, parce que la plupart des
compilateurs aujourd'hui ont des options pour insérer du code de
vérification dans certains cas. Et ce n'est pas une nouveauté.
Vérification, oui. Crash intentionnel, non.
Et moi, je peux te dire que je me suis déjà servi d'un
compilateur où il ne marchait pas -- le compilateur
généré systèmatiquement des tests pour un pointeur null
chaque fois qu'on se servait de l'opérateur * unaire.
Si tu peux te souvenir du nom de ce compilateur,
j'aimerais vraiment étudier la manière dont il génère ce
genre de test.
Le compilateur, c'était le compilateur de Green Hills. Je ne
sais pas ce qui lui en est devenu aujourd'hui.
Merci. Je vais effecteur quelques recherches sur ce
compilateur.
Il y a un autre compilateur dont on me dit qu'il faisait pareil.
J'ai un trou de mémoire en ce qui concerne son nom à l'instant,
mais à l'époque, il était assez connu pour tester tout. (Il se
vendait comme compilateur de « contrôle » ; son but n'était
pas de compiler l'exécutable qu'on livrait, mais de compiler
avec un maximum de vérifications, de façon à ce qu'on détecte un
maximum d'erreurs.)
En effet, pour que ce test soit valide pour n'importe quelles
applications, le pointeur doit se trouver sur la pile. Sinon
(le pointeur est lui-même un objet pointé se trouvant sur le
tas), l'ensemble de cette opération(test + déréférencement)
est non atomique (pas de test&set pour les déréférencements)
et le compilateur doit normalement poser un lock, sauf si le
compilateur ne génère que du code monothreadé.
Tu te moques de nous ou quoi ? Si un autre thread peut modifier
le pointeur, l'utilisateur a déjà un lock. Sinon, il a un
comportement indéfini, qui risque réelement de lui causer des
ennuis. (N'oublie pas que la lecture d'un pointeur n'est pas
forcément atomique. Au moins, pas sur un Intel.)
L'utilisateur a déjà un lock ?
Qui l'y oblige ?
Heureusement que ce n'est pas obligatoire notamment dans le
domaine de développement de certains drivers et applications
real-time.
Par contre le compilateur se doit d'avoir un comportement
consistant : le compilateur doit mettre un lock, même s'il est
peu probable qu'une application s'amuse à changer un pointeur
NULL en un pointeur valide dans une autre thread (par contre
changer un pointeur valide en un autre pointeur valide sans
lock est un cas pratique).
dieu.tout.puissant@gmail.com wrote:
S'il y a déréférencement dans ce cas-là, il y aura crash à
l'exécution. Je n'ai encore rencontré aucun compilateur qui
sacrifie la rapidité du code (génère une instruction de plus)
dans le but de provoquer un crash.
Il te manque de l'expérience, alors, parce que la plupart des
compilateurs aujourd'hui ont des options pour insérer du code de
vérification dans certains cas. Et ce n'est pas une nouveauté.
Vérification, oui. Crash intentionnel, non.
Et moi, je peux te dire que je me suis déjà servi d'un
compilateur où il ne marchait pas -- le compilateur
généré systèmatiquement des tests pour un pointeur null
chaque fois qu'on se servait de l'opérateur * unaire.
Si tu peux te souvenir du nom de ce compilateur,
j'aimerais vraiment étudier la manière dont il génère ce
genre de test.
Le compilateur, c'était le compilateur de Green Hills. Je ne
sais pas ce qui lui en est devenu aujourd'hui.
Merci. Je vais effecteur quelques recherches sur ce
compilateur.
Il y a un autre compilateur dont on me dit qu'il faisait pareil.
J'ai un trou de mémoire en ce qui concerne son nom à l'instant,
mais à l'époque, il était assez connu pour tester tout. (Il se
vendait comme compilateur de « contrôle » ; son but n'était
pas de compiler l'exécutable qu'on livrait, mais de compiler
avec un maximum de vérifications, de façon à ce qu'on détecte un
maximum d'erreurs.)
En effet, pour que ce test soit valide pour n'importe quelles
applications, le pointeur doit se trouver sur la pile. Sinon
(le pointeur est lui-même un objet pointé se trouvant sur le
tas), l'ensemble de cette opération(test + déréférencement)
est non atomique (pas de test&set pour les déréférencements)
et le compilateur doit normalement poser un lock, sauf si le
compilateur ne génère que du code monothreadé.
Tu te moques de nous ou quoi ? Si un autre thread peut modifier
le pointeur, l'utilisateur a déjà un lock. Sinon, il a un
comportement indéfini, qui risque réelement de lui causer des
ennuis. (N'oublie pas que la lecture d'un pointeur n'est pas
forcément atomique. Au moins, pas sur un Intel.)
L'utilisateur a déjà un lock ?
Qui l'y oblige ?
Heureusement que ce n'est pas obligatoire notamment dans le
domaine de développement de certains drivers et applications
real-time.
Par contre le compilateur se doit d'avoir un comportement
consistant : le compilateur doit mettre un lock, même s'il est
peu probable qu'une application s'amuse à changer un pointeur
NULL en un pointeur valide dans une autre thread (par contre
changer un pointeur valide en un autre pointeur valide sans
lock est un cas pratique).
wrote:
S'il y a déréférencement dans ce cas-là, il y aura crash à
l'exécution. Je n'ai encore rencontré aucun compilateur qui
sacrifie la rapidité du code (génère une instruction de plus)
dans le but de provoquer un crash.
Il te manque de l'expérience, alors, parce que la plupart des
compilateurs aujourd'hui ont des options pour insérer du code de
vérification dans certains cas. Et ce n'est pas une nouveauté.
Vérification, oui. Crash intentionnel, non.
Et moi, je peux te dire que je me suis déjà servi d'un
compilateur où il ne marchait pas -- le compilateur
généré systèmatiquement des tests pour un pointeur null
chaque fois qu'on se servait de l'opérateur * unaire.
Si tu peux te souvenir du nom de ce compilateur,
j'aimerais vraiment étudier la manière dont il génère ce
genre de test.
Le compilateur, c'était le compilateur de Green Hills. Je ne
sais pas ce qui lui en est devenu aujourd'hui.
Merci. Je vais effecteur quelques recherches sur ce
compilateur.
Il y a un autre compilateur dont on me dit qu'il faisait pareil.
J'ai un trou de mémoire en ce qui concerne son nom à l'instant,
mais à l'époque, il était assez connu pour tester tout. (Il se
vendait comme compilateur de « contrôle » ; son but n'était
pas de compiler l'exécutable qu'on livrait, mais de compiler
avec un maximum de vérifications, de façon à ce qu'on détecte un
maximum d'erreurs.)
En effet, pour que ce test soit valide pour n'importe quelles
applications, le pointeur doit se trouver sur la pile. Sinon
(le pointeur est lui-même un objet pointé se trouvant sur le
tas), l'ensemble de cette opération(test + déréférencement)
est non atomique (pas de test&set pour les déréférencements)
et le compilateur doit normalement poser un lock, sauf si le
compilateur ne génère que du code monothreadé.
Tu te moques de nous ou quoi ? Si un autre thread peut modifier
le pointeur, l'utilisateur a déjà un lock. Sinon, il a un
comportement indéfini, qui risque réelement de lui causer des
ennuis. (N'oublie pas que la lecture d'un pointeur n'est pas
forcément atomique. Au moins, pas sur un Intel.)
L'utilisateur a déjà un lock ?
Qui l'y oblige ?
Heureusement que ce n'est pas obligatoire notamment dans le
domaine de développement de certains drivers et applications
real-time.
Par contre le compilateur se doit d'avoir un comportement
consistant : le compilateur doit mettre un lock, même s'il est
peu probable qu'une application s'amuse à changer un pointeur
NULL en un pointeur valide dans une autre thread (par contre
changer un pointeur valide en un autre pointeur valide sans
lock est un cas pratique).
Manuel Zaccaria wrote on 17/10/2006 14:02:
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
si tu savais comme je m'en cogne de ces indéfinitions là !!
pour qui écrit un sample jamais publié (surtout pas utilisé)
c'est surement d'une haute importance; quand on est derrière
un vrai compilo pour du vrai code, le comportement est tout à
fait complètement défini.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un
compilo que je n'utiliserais jamais estime indéfini.
Sinon on utilise un pointeur, pas une référence. Faut pas
mélanger des concepts qui visent des buts différents.
tu peux nous parler un peu plus de ces "buts" ?
pour moi (et pour le compilo quand il l'utilise) une référence
est un pointeur.
Manuel Zaccaria wrote on 17/10/2006 14:02:
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
si tu savais comme je m'en cogne de ces indéfinitions là !!
pour qui écrit un sample jamais publié (surtout pas utilisé)
c'est surement d'une haute importance; quand on est derrière
un vrai compilo pour du vrai code, le comportement est tout à
fait complètement défini.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un
compilo que je n'utiliserais jamais estime indéfini.
Sinon on utilise un pointeur, pas une référence. Faut pas
mélanger des concepts qui visent des buts différents.
tu peux nous parler un peu plus de ces "buts" ?
pour moi (et pour le compilo quand il l'utilise) une référence
est un pointeur.
Manuel Zaccaria wrote on 17/10/2006 14:02:
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
si tu savais comme je m'en cogne de ces indéfinitions là !!
pour qui écrit un sample jamais publié (surtout pas utilisé)
c'est surement d'une haute importance; quand on est derrière
un vrai compilo pour du vrai code, le comportement est tout à
fait complètement défini.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un
compilo que je n'utiliserais jamais estime indéfini.
Sinon on utilise un pointeur, pas une référence. Faut pas
mélanger des concepts qui visent des buts différents.
tu peux nous parler un peu plus de ces "buts" ?
pour moi (et pour le compilo quand il l'utilise) une référence
est un pointeur.
Manuel Zaccaria wrote on 17/10/2006 14:02:Est ce que *first a un comportement defini si first vaut NULL ?
quelle importance puisqu'il N'est PAS déréférencé ...
Bien sur que si... petit rappel:
bien sur que non...class A {
A& a;
A(A another) : a(another) { ... }
ici ce doit être A(A&) (indiqué le 28/09 à 22:11)
/*virtual*/ void execute() { ... }
void crash() {
a.execute();
}
personne n'a indiqué qu'un "vrai" déréférencement ne plantera pas.
c'est même une évidence et donc qui s'autorisera à avoir des références
nulles devra les tester, or "tester cette valeur ne conduira pas à un code
très clean mais bon ..." (indiqué le 28/09 à 20:49)
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
si tu savais comme je m'en cogne de ces indéfinitions là !!
pour qui écrit un sample jamais publié (surtout pas utilisé) c'est
surement d'une haute importance; quand on est derrière un vrai compilo
pour du vrai code, le comportement est tout à fait complètement défini.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un compilo que je
n'utiliserais jamais estime indéfini.
J'ajoute que ce serait contre-productif
(une pessimisation). Il devient tout-à-coup nécessaire de tester
dans les fonctions membres l'adresse de la référence à coup de :
et pourquoi donc "nécessaire" ??? si (dans l'esprit des réponses données
au PO) il s'agit d'un noeud d'un btree, je sais surement par une autre
donnée membre qui est le noeud principal, je sais qu'il n'a pas de père et
n'aurait aucune "nécessité" à déréferencer ce pointeur (!) que je sais
null.
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
non le premier but est de fluidifier l'écriture, accessoirement de forcer
l'initialisation avec une valeur non nulle.
j'ai dit "forcer", je ne dis pas empêcher; certain évoquent des compilos
qui se rendrait compte de cela, je préférerais pour ma part les compilos
qui n'introduisent pas du soi-disant code de contrôle totalement inutile
et couteux.
quant à "garantir que l'object existe" ... dis moi que "l'erreur" ci-après
est détectée par ton compilo et on parlera de l'argument.
int* p = new int[1];
int& r = *p;
delete [] p;
r;
Sinon on utilise un pointeur, pas une référence. Faut pas mélanger
des concepts qui visent des buts différents.
tu peux nous parler un peu plus de ces "buts" ?
pour moi (et pour le compilo quand il l'utilise) une référence est un
pointeur.
Quand on se bat contre le compilateur, on est toujours perdant!
?!??
Mais quel est l'intérêt de faire ça ? Je n'en vois aucun.
ne pas le voir n'implique pas que cela puisse exister.
Mes 2 centimes suisses,
je croyais la Suisse plus riche ;)
Manuel Zaccaria wrote on 17/10/2006 14:02:
Est ce que *first a un comportement defini si first vaut NULL ?
quelle importance puisqu'il N'est PAS déréférencé ...
Bien sur que si... petit rappel:
bien sur que non...
class A {
A& a;
A(A another) : a(another) { ... }
ici ce doit être A(A&) (indiqué le 28/09 à 22:11)
/*virtual*/ void execute() { ... }
void crash() {
a.execute();
}
personne n'a indiqué qu'un "vrai" déréférencement ne plantera pas.
c'est même une évidence et donc qui s'autorisera à avoir des références
nulles devra les tester, or "tester cette valeur ne conduira pas à un code
très clean mais bon ..." (indiqué le 28/09 à 20:49)
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
si tu savais comme je m'en cogne de ces indéfinitions là !!
pour qui écrit un sample jamais publié (surtout pas utilisé) c'est
surement d'une haute importance; quand on est derrière un vrai compilo
pour du vrai code, le comportement est tout à fait complètement défini.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un compilo que je
n'utiliserais jamais estime indéfini.
J'ajoute que ce serait contre-productif
(une pessimisation). Il devient tout-à-coup nécessaire de tester
dans les fonctions membres l'adresse de la référence à coup de :
et pourquoi donc "nécessaire" ??? si (dans l'esprit des réponses données
au PO) il s'agit d'un noeud d'un btree, je sais surement par une autre
donnée membre qui est le noeud principal, je sais qu'il n'a pas de père et
n'aurait aucune "nécessité" à déréferencer ce pointeur (!) que je sais
null.
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
non le premier but est de fluidifier l'écriture, accessoirement de forcer
l'initialisation avec une valeur non nulle.
j'ai dit "forcer", je ne dis pas empêcher; certain évoquent des compilos
qui se rendrait compte de cela, je préférerais pour ma part les compilos
qui n'introduisent pas du soi-disant code de contrôle totalement inutile
et couteux.
quant à "garantir que l'object existe" ... dis moi que "l'erreur" ci-après
est détectée par ton compilo et on parlera de l'argument.
int* p = new int[1];
int& r = *p;
delete [] p;
r;
Sinon on utilise un pointeur, pas une référence. Faut pas mélanger
des concepts qui visent des buts différents.
tu peux nous parler un peu plus de ces "buts" ?
pour moi (et pour le compilo quand il l'utilise) une référence est un
pointeur.
Quand on se bat contre le compilateur, on est toujours perdant!
?!??
Mais quel est l'intérêt de faire ça ? Je n'en vois aucun.
ne pas le voir n'implique pas que cela puisse exister.
Mes 2 centimes suisses,
je croyais la Suisse plus riche ;)
Manuel Zaccaria wrote on 17/10/2006 14:02:Est ce que *first a un comportement defini si first vaut NULL ?
quelle importance puisqu'il N'est PAS déréférencé ...
Bien sur que si... petit rappel:
bien sur que non...class A {
A& a;
A(A another) : a(another) { ... }
ici ce doit être A(A&) (indiqué le 28/09 à 22:11)
/*virtual*/ void execute() { ... }
void crash() {
a.execute();
}
personne n'a indiqué qu'un "vrai" déréférencement ne plantera pas.
c'est même une évidence et donc qui s'autorisera à avoir des références
nulles devra les tester, or "tester cette valeur ne conduira pas à un code
très clean mais bon ..." (indiqué le 28/09 à 20:49)
Ceci dit, je ne vois aucun intérêt à initialiser une référence
avec un pointeur nul. Comme il a déjà été dit et répété, c'est
un comportement indéfini.
si tu savais comme je m'en cogne de ces indéfinitions là !!
pour qui écrit un sample jamais publié (surtout pas utilisé) c'est
surement d'une haute importance; quand on est derrière un vrai compilo
pour du vrai code, le comportement est tout à fait complètement défini.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un compilo que je
n'utiliserais jamais estime indéfini.
J'ajoute que ce serait contre-productif
(une pessimisation). Il devient tout-à-coup nécessaire de tester
dans les fonctions membres l'adresse de la référence à coup de :
et pourquoi donc "nécessaire" ??? si (dans l'esprit des réponses données
au PO) il s'agit d'un noeud d'un btree, je sais surement par une autre
donnée membre qui est le noeud principal, je sais qu'il n'a pas de père et
n'aurait aucune "nécessité" à déréferencer ce pointeur (!) que je sais
null.
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
non le premier but est de fluidifier l'écriture, accessoirement de forcer
l'initialisation avec une valeur non nulle.
j'ai dit "forcer", je ne dis pas empêcher; certain évoquent des compilos
qui se rendrait compte de cela, je préférerais pour ma part les compilos
qui n'introduisent pas du soi-disant code de contrôle totalement inutile
et couteux.
quant à "garantir que l'object existe" ... dis moi que "l'erreur" ci-après
est détectée par ton compilo et on parlera de l'argument.
int* p = new int[1];
int& r = *p;
delete [] p;
r;
Sinon on utilise un pointeur, pas une référence. Faut pas mélanger
des concepts qui visent des buts différents.
tu peux nous parler un peu plus de ces "buts" ?
pour moi (et pour le compilo quand il l'utilise) une référence est un
pointeur.
Quand on se bat contre le compilateur, on est toujours perdant!
?!??
Mais quel est l'intérêt de faire ça ? Je n'en vois aucun.
ne pas le voir n'implique pas que cela puisse exister.
Mes 2 centimes suisses,
je croyais la Suisse plus riche ;)
Sylvain schrieb:qui s'autorisera à avoir des références nulles devra les tester
On les teste comment, sachant que le compilateur a le droit d'éliminer
le test ?
De plus, rien ne garantit que la référence reste nulle lorsque
l'héritage entre en jeu !
Question à 0,02 : Qu'affiche-t-il le programme suivant:
struct Base {
int i;
};
struct Derived : public Base {
virtual ~Derived() {}
};
Réponse : Chez moi cela donne
Frtzragngvba snhyg (pber qhzcrq)
Sylvain schrieb:
qui s'autorisera à avoir des références nulles devra les tester
On les teste comment, sachant que le compilateur a le droit d'éliminer
le test ?
De plus, rien ne garantit que la référence reste nulle lorsque
l'héritage entre en jeu !
Question à 0,02 : Qu'affiche-t-il le programme suivant:
struct Base {
int i;
};
struct Derived : public Base {
virtual ~Derived() {}
};
Réponse : Chez moi cela donne
Frtzragngvba snhyg (pber qhzcrq)
Sylvain schrieb:qui s'autorisera à avoir des références nulles devra les tester
On les teste comment, sachant que le compilateur a le droit d'éliminer
le test ?
De plus, rien ne garantit que la référence reste nulle lorsque
l'héritage entre en jeu !
Question à 0,02 : Qu'affiche-t-il le programme suivant:
struct Base {
int i;
};
struct Derived : public Base {
virtual ~Derived() {}
};
Réponse : Chez moi cela donne
Frtzragngvba snhyg (pber qhzcrq)
wrote:wrote:
S'il y a déréférencement dans ce cas-là, il y aura crash à
l'exécution. Je n'ai encore rencontré aucun compilateur qui
sacrifie la rapidité du code (génère une instruction de plus)
dans le but de provoquer un crash.
Il te manque de l'expérience, alors, parce que la plupart des
compilateurs aujourd'hui ont des options pour insérer du code de
vérification dans certains cas. Et ce n'est pas une nouveauté.
Vérification, oui. Crash intentionnel, non.
C'est l'équivalent d'un assert. Avec g++, j'ai bien un core dump
sous Unix ; avec VC++, j'ai le pop-up d'une erreur sous
Windows, avec le choix d'aborter complétement, ou de continuer
sous le debuggeur.
Et moi, je peux te dire que je me suis déjà servi d'un
compilateur où il ne marchait pas -- le compilateur
généré systèmatiquement des tests pour un pointeur null
chaque fois qu'on se servait de l'opérateur * unaire.
Si tu peux te souvenir du nom de ce compilateur,
j'aimerais vraiment étudier la manière dont il génère ce
genre de test.
Le compilateur, c'était le compilateur de Green Hills. Je ne
sais pas ce qui lui en est devenu aujourd'hui.
Merci. Je vais effecteur quelques recherches sur ce
compilateur.
Il se vendait encore il y a peu. Je ne sais pas si l'option pour
générer les vérifications y est toujours, mais j'imagine que si.
En revanche, dans le mesure qu'il n'ont plus leur propre
front-end pour le C++, et que le C aujourd'hui permet
explicitement l'expression &*p, où p est un pointeur nul, c'est
peu probable que la vérification se fait encore lors de
l'initialisation d'une référence (qui doit bien apparaître au
back-end comme un &*p).
Avec la plupart des compilateurs, tu risque d'avoir des
problèmes si tu fais des choses du genre :
Derived* pd = NULL ;
Base& r = *pd ;
Base* pb = &r ;
if ( pb == NULL ) ...
La conversion d'un Derived* en Base* peut exiger en fait une
changement de l'adresse. Qui ne doit pas avoir lieu si le
pointeur est null. Normalement, donc, le compilateur génère du
code pour tester ce cas. S'il voit que le pointeur est
déréférencé, pour initialiser une référence, il sait qu'il n' est
pas nul, et peut donc supprimer le test. Avec comme résultat que
le pointeur n'est plus nul.
Il y a un autre compilateur dont on me dit qu'il faisait pareil.
J'ai un trou de mémoire en ce qui concerne son nom à l'instant,
mais à l'époque, il était assez connu pour tester tout. (Il se
vendait comme compilateur de « contrôle » ; son but n'était
pas de compiler l'exécutable qu'on livrait, mais de compiler
avec un maximum de vérifications, de façon à ce qu'on détecte un
maximum d'erreurs.)
Ça m'est revenu, le nom du compilateur. C'est Center Line (ou
quelque chose du genre). Et il existe encore (bien que ça fait
des années que je n'en ai plus entendu parler) :
http://www.ics.com/products/centerline/index.html. Parmi les
features : « Locates incorrect pointer values, illegal array
indices, bad function arguments, type mismatches, and
uninitialized variables ».
À l'époque où j'entendais parler (début des années 1990s), on me
disait que les temps d'exécution était deux ou trois fois plus
lent, parfois plus, qu'avec le compilateur Sun. Le marché visé
était uniquement des builds de déboggage. Avec l'amélioration de
l'analyse statique (pour pouvoir supprimer les tests qu'on sait
n'échouera pas) et l'augmentation de la vitesse des machines, ça
ne m'étonnerait pas qu'il puisse servir à la production.
Aussi à l'époque, et d'après ce qu'on m'a dit (je n'ai jamais pu
m'en servir), la taille d'un pointeur était trois fois plus
grand que sous Sun CC ; physiquement, le pointeur C/C++
contenait trois pointeurs hardware : la valeur courante, et les
deux bornes. (La norme C a été soigneusement formulée pour
permettre, voire même encourager une telle implémentation.)En effet, pour que ce test soit valide pour n'importe quelles
applications, le pointeur doit se trouver sur la pile. Sinon
(le pointeur est lui-même un objet pointé se trouvant sur le
tas), l'ensemble de cette opération(test + déréférencement)
est non atomique (pas de test&set pour les déréférencements)
et le compilateur doit normalement poser un lock, sauf si le
compilateur ne génère que du code monothreadé.
Tu te moques de nous ou quoi ? Si un autre thread peut modifier
le pointeur, l'utilisateur a déjà un lock. Sinon, il a un
comportement indéfini, qui risque réelement de lui causer des
ennuis. (N'oublie pas que la lecture d'un pointeur n'est pas
forcément atomique. Au moins, pas sur un Intel.)
L'utilisateur a déjà un lock ?
Il en a intérêt. Tu ne peux pas modifier un objet en mémoire
dans un thread sans que tous les threads qui y accèdent
protègent leurs accès.
Qui l'y oblige ?
Posix, pour un. La façon que travaille l'hardware moderne, pour
l'autre.
Heureusement que ce n'est pas obligatoire notamment dans le
domaine de développement de certains drivers et applications
real-time.
Certes, il existe d'autres solutions. Mais pas en C++. (Pas
encore, en tout cas -- Microsoft a annoncé qu'il vont définir
la signification de volatile pour qu'il marche. Mais ce n'est
pas le cas dans VC++ 8, au moins d'après les code généré.)
::operator<< (402038h)]
Par contre le compilateur se doit d'avoir un comportement
consistant : le compilateur doit mettre un lock, même s'il est
peu probable qu'une application s'amuse à changer un pointeur
NULL en un pointeur valide dans une autre thread (par contre
changer un pointeur valide en un autre pointeur valide sans
lock est un cas pratique).
Pratique ou non, il ne marche pas. Il risque de donner les
apparences de marcher sur un ancien processeur, avec un
compilateur primitif, mais au plus tard, dès que tu as un
multi-core, ou un bon optimisateur, tu risques d'avoir des
problèmes. Même dans le cas le plus favorable, tu risques
fortement des surprises. Considère :
thread 1 :
p = new MyClass ;
thread 2 :
p->someMember ;
Le compilateur risque de réordonner les écritures de façon à ce
que l'écriture physique de p en thread 1 précède l'écriture des
variables membre dans le constructeur de MyClass ; thread 2
pourrait donc accéder à une variable non initialisée. Tous les
compilateurs que je connais réordonne les écritures dans
certains cas -- je me rappelle l'avoir vu dans MS C, version
1.0. C'est une partie essentielle de l'optimisation. Avec les
compilateurs courants (VC++ pré version 7, et peut-être
pré-version 8, par exemple), il suffisait de mettre le
constructeur dans une source différente que son appel pour
inhiber l'optimisation, mais VC++ 8, comme la plupart des
compilateurs modernes, a des options pour optimiser au delà des
frontières d'une unité de compilation.
Et évidemment, même si le compilateur n'optimise rien, dans un
processeur multi-core, au moins de prendre des précautions
précises (instructions membar sur Sparc, fence sur AMD, et
peut-être Intel, etc.), il n'y a aucune garantie que une
CPU/core voire les écritures dans le même ordre qu'ils ont été
émises par l'autre.
dieu.tout.puissant@gmail.com wrote:
dieu.tout.puissant@gmail.com wrote:
S'il y a déréférencement dans ce cas-là, il y aura crash à
l'exécution. Je n'ai encore rencontré aucun compilateur qui
sacrifie la rapidité du code (génère une instruction de plus)
dans le but de provoquer un crash.
Il te manque de l'expérience, alors, parce que la plupart des
compilateurs aujourd'hui ont des options pour insérer du code de
vérification dans certains cas. Et ce n'est pas une nouveauté.
Vérification, oui. Crash intentionnel, non.
C'est l'équivalent d'un assert. Avec g++, j'ai bien un core dump
sous Unix ; avec VC++, j'ai le pop-up d'une erreur sous
Windows, avec le choix d'aborter complétement, ou de continuer
sous le debuggeur.
Et moi, je peux te dire que je me suis déjà servi d'un
compilateur où il ne marchait pas -- le compilateur
généré systèmatiquement des tests pour un pointeur null
chaque fois qu'on se servait de l'opérateur * unaire.
Si tu peux te souvenir du nom de ce compilateur,
j'aimerais vraiment étudier la manière dont il génère ce
genre de test.
Le compilateur, c'était le compilateur de Green Hills. Je ne
sais pas ce qui lui en est devenu aujourd'hui.
Merci. Je vais effecteur quelques recherches sur ce
compilateur.
Il se vendait encore il y a peu. Je ne sais pas si l'option pour
générer les vérifications y est toujours, mais j'imagine que si.
En revanche, dans le mesure qu'il n'ont plus leur propre
front-end pour le C++, et que le C aujourd'hui permet
explicitement l'expression &*p, où p est un pointeur nul, c'est
peu probable que la vérification se fait encore lors de
l'initialisation d'une référence (qui doit bien apparaître au
back-end comme un &*p).
Avec la plupart des compilateurs, tu risque d'avoir des
problèmes si tu fais des choses du genre :
Derived* pd = NULL ;
Base& r = *pd ;
Base* pb = &r ;
if ( pb == NULL ) ...
La conversion d'un Derived* en Base* peut exiger en fait une
changement de l'adresse. Qui ne doit pas avoir lieu si le
pointeur est null. Normalement, donc, le compilateur génère du
code pour tester ce cas. S'il voit que le pointeur est
déréférencé, pour initialiser une référence, il sait qu'il n' est
pas nul, et peut donc supprimer le test. Avec comme résultat que
le pointeur n'est plus nul.
Il y a un autre compilateur dont on me dit qu'il faisait pareil.
J'ai un trou de mémoire en ce qui concerne son nom à l'instant,
mais à l'époque, il était assez connu pour tester tout. (Il se
vendait comme compilateur de « contrôle » ; son but n'était
pas de compiler l'exécutable qu'on livrait, mais de compiler
avec un maximum de vérifications, de façon à ce qu'on détecte un
maximum d'erreurs.)
Ça m'est revenu, le nom du compilateur. C'est Center Line (ou
quelque chose du genre). Et il existe encore (bien que ça fait
des années que je n'en ai plus entendu parler) :
http://www.ics.com/products/centerline/index.html. Parmi les
features : « Locates incorrect pointer values, illegal array
indices, bad function arguments, type mismatches, and
uninitialized variables ».
À l'époque où j'entendais parler (début des années 1990s), on me
disait que les temps d'exécution était deux ou trois fois plus
lent, parfois plus, qu'avec le compilateur Sun. Le marché visé
était uniquement des builds de déboggage. Avec l'amélioration de
l'analyse statique (pour pouvoir supprimer les tests qu'on sait
n'échouera pas) et l'augmentation de la vitesse des machines, ça
ne m'étonnerait pas qu'il puisse servir à la production.
Aussi à l'époque, et d'après ce qu'on m'a dit (je n'ai jamais pu
m'en servir), la taille d'un pointeur était trois fois plus
grand que sous Sun CC ; physiquement, le pointeur C/C++
contenait trois pointeurs hardware : la valeur courante, et les
deux bornes. (La norme C a été soigneusement formulée pour
permettre, voire même encourager une telle implémentation.)
En effet, pour que ce test soit valide pour n'importe quelles
applications, le pointeur doit se trouver sur la pile. Sinon
(le pointeur est lui-même un objet pointé se trouvant sur le
tas), l'ensemble de cette opération(test + déréférencement)
est non atomique (pas de test&set pour les déréférencements)
et le compilateur doit normalement poser un lock, sauf si le
compilateur ne génère que du code monothreadé.
Tu te moques de nous ou quoi ? Si un autre thread peut modifier
le pointeur, l'utilisateur a déjà un lock. Sinon, il a un
comportement indéfini, qui risque réelement de lui causer des
ennuis. (N'oublie pas que la lecture d'un pointeur n'est pas
forcément atomique. Au moins, pas sur un Intel.)
L'utilisateur a déjà un lock ?
Il en a intérêt. Tu ne peux pas modifier un objet en mémoire
dans un thread sans que tous les threads qui y accèdent
protègent leurs accès.
Qui l'y oblige ?
Posix, pour un. La façon que travaille l'hardware moderne, pour
l'autre.
Heureusement que ce n'est pas obligatoire notamment dans le
domaine de développement de certains drivers et applications
real-time.
Certes, il existe d'autres solutions. Mais pas en C++. (Pas
encore, en tout cas -- Microsoft a annoncé qu'il vont définir
la signification de volatile pour qu'il marche. Mais ce n'est
pas le cas dans VC++ 8, au moins d'après les code généré.)
::operator<< (402038h)]
Par contre le compilateur se doit d'avoir un comportement
consistant : le compilateur doit mettre un lock, même s'il est
peu probable qu'une application s'amuse à changer un pointeur
NULL en un pointeur valide dans une autre thread (par contre
changer un pointeur valide en un autre pointeur valide sans
lock est un cas pratique).
Pratique ou non, il ne marche pas. Il risque de donner les
apparences de marcher sur un ancien processeur, avec un
compilateur primitif, mais au plus tard, dès que tu as un
multi-core, ou un bon optimisateur, tu risques d'avoir des
problèmes. Même dans le cas le plus favorable, tu risques
fortement des surprises. Considère :
thread 1 :
p = new MyClass ;
thread 2 :
p->someMember ;
Le compilateur risque de réordonner les écritures de façon à ce
que l'écriture physique de p en thread 1 précède l'écriture des
variables membre dans le constructeur de MyClass ; thread 2
pourrait donc accéder à une variable non initialisée. Tous les
compilateurs que je connais réordonne les écritures dans
certains cas -- je me rappelle l'avoir vu dans MS C, version
1.0. C'est une partie essentielle de l'optimisation. Avec les
compilateurs courants (VC++ pré version 7, et peut-être
pré-version 8, par exemple), il suffisait de mettre le
constructeur dans une source différente que son appel pour
inhiber l'optimisation, mais VC++ 8, comme la plupart des
compilateurs modernes, a des options pour optimiser au delà des
frontières d'une unité de compilation.
Et évidemment, même si le compilateur n'optimise rien, dans un
processeur multi-core, au moins de prendre des précautions
précises (instructions membar sur Sparc, fence sur AMD, et
peut-être Intel, etc.), il n'y a aucune garantie que une
CPU/core voire les écritures dans le même ordre qu'ils ont été
émises par l'autre.
wrote:wrote:
S'il y a déréférencement dans ce cas-là, il y aura crash à
l'exécution. Je n'ai encore rencontré aucun compilateur qui
sacrifie la rapidité du code (génère une instruction de plus)
dans le but de provoquer un crash.
Il te manque de l'expérience, alors, parce que la plupart des
compilateurs aujourd'hui ont des options pour insérer du code de
vérification dans certains cas. Et ce n'est pas une nouveauté.
Vérification, oui. Crash intentionnel, non.
C'est l'équivalent d'un assert. Avec g++, j'ai bien un core dump
sous Unix ; avec VC++, j'ai le pop-up d'une erreur sous
Windows, avec le choix d'aborter complétement, ou de continuer
sous le debuggeur.
Et moi, je peux te dire que je me suis déjà servi d'un
compilateur où il ne marchait pas -- le compilateur
généré systèmatiquement des tests pour un pointeur null
chaque fois qu'on se servait de l'opérateur * unaire.
Si tu peux te souvenir du nom de ce compilateur,
j'aimerais vraiment étudier la manière dont il génère ce
genre de test.
Le compilateur, c'était le compilateur de Green Hills. Je ne
sais pas ce qui lui en est devenu aujourd'hui.
Merci. Je vais effecteur quelques recherches sur ce
compilateur.
Il se vendait encore il y a peu. Je ne sais pas si l'option pour
générer les vérifications y est toujours, mais j'imagine que si.
En revanche, dans le mesure qu'il n'ont plus leur propre
front-end pour le C++, et que le C aujourd'hui permet
explicitement l'expression &*p, où p est un pointeur nul, c'est
peu probable que la vérification se fait encore lors de
l'initialisation d'une référence (qui doit bien apparaître au
back-end comme un &*p).
Avec la plupart des compilateurs, tu risque d'avoir des
problèmes si tu fais des choses du genre :
Derived* pd = NULL ;
Base& r = *pd ;
Base* pb = &r ;
if ( pb == NULL ) ...
La conversion d'un Derived* en Base* peut exiger en fait une
changement de l'adresse. Qui ne doit pas avoir lieu si le
pointeur est null. Normalement, donc, le compilateur génère du
code pour tester ce cas. S'il voit que le pointeur est
déréférencé, pour initialiser une référence, il sait qu'il n' est
pas nul, et peut donc supprimer le test. Avec comme résultat que
le pointeur n'est plus nul.
Il y a un autre compilateur dont on me dit qu'il faisait pareil.
J'ai un trou de mémoire en ce qui concerne son nom à l'instant,
mais à l'époque, il était assez connu pour tester tout. (Il se
vendait comme compilateur de « contrôle » ; son but n'était
pas de compiler l'exécutable qu'on livrait, mais de compiler
avec un maximum de vérifications, de façon à ce qu'on détecte un
maximum d'erreurs.)
Ça m'est revenu, le nom du compilateur. C'est Center Line (ou
quelque chose du genre). Et il existe encore (bien que ça fait
des années que je n'en ai plus entendu parler) :
http://www.ics.com/products/centerline/index.html. Parmi les
features : « Locates incorrect pointer values, illegal array
indices, bad function arguments, type mismatches, and
uninitialized variables ».
À l'époque où j'entendais parler (début des années 1990s), on me
disait que les temps d'exécution était deux ou trois fois plus
lent, parfois plus, qu'avec le compilateur Sun. Le marché visé
était uniquement des builds de déboggage. Avec l'amélioration de
l'analyse statique (pour pouvoir supprimer les tests qu'on sait
n'échouera pas) et l'augmentation de la vitesse des machines, ça
ne m'étonnerait pas qu'il puisse servir à la production.
Aussi à l'époque, et d'après ce qu'on m'a dit (je n'ai jamais pu
m'en servir), la taille d'un pointeur était trois fois plus
grand que sous Sun CC ; physiquement, le pointeur C/C++
contenait trois pointeurs hardware : la valeur courante, et les
deux bornes. (La norme C a été soigneusement formulée pour
permettre, voire même encourager une telle implémentation.)En effet, pour que ce test soit valide pour n'importe quelles
applications, le pointeur doit se trouver sur la pile. Sinon
(le pointeur est lui-même un objet pointé se trouvant sur le
tas), l'ensemble de cette opération(test + déréférencement)
est non atomique (pas de test&set pour les déréférencements)
et le compilateur doit normalement poser un lock, sauf si le
compilateur ne génère que du code monothreadé.
Tu te moques de nous ou quoi ? Si un autre thread peut modifier
le pointeur, l'utilisateur a déjà un lock. Sinon, il a un
comportement indéfini, qui risque réelement de lui causer des
ennuis. (N'oublie pas que la lecture d'un pointeur n'est pas
forcément atomique. Au moins, pas sur un Intel.)
L'utilisateur a déjà un lock ?
Il en a intérêt. Tu ne peux pas modifier un objet en mémoire
dans un thread sans que tous les threads qui y accèdent
protègent leurs accès.
Qui l'y oblige ?
Posix, pour un. La façon que travaille l'hardware moderne, pour
l'autre.
Heureusement que ce n'est pas obligatoire notamment dans le
domaine de développement de certains drivers et applications
real-time.
Certes, il existe d'autres solutions. Mais pas en C++. (Pas
encore, en tout cas -- Microsoft a annoncé qu'il vont définir
la signification de volatile pour qu'il marche. Mais ce n'est
pas le cas dans VC++ 8, au moins d'après les code généré.)
::operator<< (402038h)]
Par contre le compilateur se doit d'avoir un comportement
consistant : le compilateur doit mettre un lock, même s'il est
peu probable qu'une application s'amuse à changer un pointeur
NULL en un pointeur valide dans une autre thread (par contre
changer un pointeur valide en un autre pointeur valide sans
lock est un cas pratique).
Pratique ou non, il ne marche pas. Il risque de donner les
apparences de marcher sur un ancien processeur, avec un
compilateur primitif, mais au plus tard, dès que tu as un
multi-core, ou un bon optimisateur, tu risques d'avoir des
problèmes. Même dans le cas le plus favorable, tu risques
fortement des surprises. Considère :
thread 1 :
p = new MyClass ;
thread 2 :
p->someMember ;
Le compilateur risque de réordonner les écritures de façon à ce
que l'écriture physique de p en thread 1 précède l'écriture des
variables membre dans le constructeur de MyClass ; thread 2
pourrait donc accéder à une variable non initialisée. Tous les
compilateurs que je connais réordonne les écritures dans
certains cas -- je me rappelle l'avoir vu dans MS C, version
1.0. C'est une partie essentielle de l'optimisation. Avec les
compilateurs courants (VC++ pré version 7, et peut-être
pré-version 8, par exemple), il suffisait de mettre le
constructeur dans une source différente que son appel pour
inhiber l'optimisation, mais VC++ 8, comme la plupart des
compilateurs modernes, a des options pour optimiser au delà des
frontières d'une unité de compilation.
Et évidemment, même si le compilateur n'optimise rien, dans un
processeur multi-core, au moins de prendre des précautions
précises (instructions membar sur Sparc, fence sur AMD, et
peut-être Intel, etc.), il n'y a aucune garantie que une
CPU/core voire les écritures dans le même ordre qu'ils ont été
émises par l'autre.
personne n'a indiqué qu'un "vrai" déréférencement ne plantera pas.
Il n'y a pas de "vrai" ou de "faux" déréférencement. Il y a ou il n'y a
pas déréférencement. La cuisine interne du compilateur ne nous concerne pas.
c'est même une évidence et donc qui s'autorisera à avoir des références
nulles devra les tester, or "tester cette valeur ne conduira pas à un code
très clean mais bon ..." (indiqué le 28/09 à 20:49)
Mais " A() : a(*this) {} " fait l'affaire. Pourquoi NULL ?
pour qui écrit un sample jamais publié (surtout pas utilisé) c'est
surement d'une haute importance; quand on est derrière un vrai compilo
pour du vrai code, le comportement est tout à fait complètement défini.
Y'a des faux copilos et du faux code maintenant ? Whouaa, j'apprend
quelque chose tous les jours. Merci Sylvain.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un compilo que je
n'utiliserais jamais estime indéfini.
Tu n'utilises aucun compilateur ? Car c'est, à ma connaîssance, un
comportement indéfini dans tous les compilateurs.
Utiliser une référence comme un pointeur, c'est juste de l'obfuscation.
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
non le premier but est de fluidifier l'écriture, accessoirement de forcer
l'initialisation avec une valeur non nulle.
A l'envers.
Le premier but est de forcer l'initialisation avec une valeur non nulle,
accessoirement de fluidifier l'écriture.
Après ça, même un if(p!=0) ou if(&r!=0) est indéfini.
Une référence ne change pas d'identité.
Comme James l'a dit et répété, le compilateur a totalement le droit
d'ignorer et optimiser (lire supprimer) le test "if(&ref != NULL)"
car il "sait" à l'avance que c'est "impossible".
int& r = *(int*)0;
Quelle est l'utilité de r ?
Plus sérieusement, dans le cas du noeud de btree, qu'est-ce qui
empêche d'utiliser this plutôt que NULL. C'est permi par la norme
et on obtient le résultat voulu.
personne n'a indiqué qu'un "vrai" déréférencement ne plantera pas.
Il n'y a pas de "vrai" ou de "faux" déréférencement. Il y a ou il n'y a
pas déréférencement. La cuisine interne du compilateur ne nous concerne pas.
c'est même une évidence et donc qui s'autorisera à avoir des références
nulles devra les tester, or "tester cette valeur ne conduira pas à un code
très clean mais bon ..." (indiqué le 28/09 à 20:49)
Mais " A() : a(*this) {} " fait l'affaire. Pourquoi NULL ?
pour qui écrit un sample jamais publié (surtout pas utilisé) c'est
surement d'une haute importance; quand on est derrière un vrai compilo
pour du vrai code, le comportement est tout à fait complètement défini.
Y'a des faux copilos et du faux code maintenant ? Whouaa, j'apprend
quelque chose tous les jours. Merci Sylvain.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un compilo que je
n'utiliserais jamais estime indéfini.
Tu n'utilises aucun compilateur ? Car c'est, à ma connaîssance, un
comportement indéfini dans tous les compilateurs.
Utiliser une référence comme un pointeur, c'est juste de l'obfuscation.
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
non le premier but est de fluidifier l'écriture, accessoirement de forcer
l'initialisation avec une valeur non nulle.
A l'envers.
Le premier but est de forcer l'initialisation avec une valeur non nulle,
accessoirement de fluidifier l'écriture.
Après ça, même un if(p!=0) ou if(&r!=0) est indéfini.
Une référence ne change pas d'identité.
Comme James l'a dit et répété, le compilateur a totalement le droit
d'ignorer et optimiser (lire supprimer) le test "if(&ref != NULL)"
car il "sait" à l'avance que c'est "impossible".
int& r = *(int*)0;
Quelle est l'utilité de r ?
Plus sérieusement, dans le cas du noeud de btree, qu'est-ce qui
empêche d'utiliser this plutôt que NULL. C'est permi par la norme
et on obtient le résultat voulu.
personne n'a indiqué qu'un "vrai" déréférencement ne plantera pas.
Il n'y a pas de "vrai" ou de "faux" déréférencement. Il y a ou il n'y a
pas déréférencement. La cuisine interne du compilateur ne nous concerne pas.
c'est même une évidence et donc qui s'autorisera à avoir des références
nulles devra les tester, or "tester cette valeur ne conduira pas à un code
très clean mais bon ..." (indiqué le 28/09 à 20:49)
Mais " A() : a(*this) {} " fait l'affaire. Pourquoi NULL ?
pour qui écrit un sample jamais publié (surtout pas utilisé) c'est
surement d'une haute importance; quand on est derrière un vrai compilo
pour du vrai code, le comportement est tout à fait complètement défini.
Y'a des faux copilos et du faux code maintenant ? Whouaa, j'apprend
quelque chose tous les jours. Merci Sylvain.
et pour résumer les 2 pts: je me cogne de savoir ce qu'un compilo que je
n'utiliserais jamais estime indéfini.
Tu n'utilises aucun compilateur ? Car c'est, à ma connaîssance, un
comportement indéfini dans tous les compilateurs.
Utiliser une référence comme un pointeur, c'est juste de l'obfuscation.
AMHA, le but des références est justement de GARANTIR que l'objet
existe (this est toujours != 0).
non le premier but est de fluidifier l'écriture, accessoirement de forcer
l'initialisation avec une valeur non nulle.
A l'envers.
Le premier but est de forcer l'initialisation avec une valeur non nulle,
accessoirement de fluidifier l'écriture.
Après ça, même un if(p!=0) ou if(&r!=0) est indéfini.
Une référence ne change pas d'identité.
Comme James l'a dit et répété, le compilateur a totalement le droit
d'ignorer et optimiser (lire supprimer) le test "if(&ref != NULL)"
car il "sait" à l'avance que c'est "impossible".
int& r = *(int*)0;
Quelle est l'utilité de r ?
Plus sérieusement, dans le cas du noeud de btree, qu'est-ce qui
empêche d'utiliser this plutôt que NULL. C'est permi par la norme
et on obtient le résultat voulu.