 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Amerio Guest
|
Posted: Mon Jan 10, 2005 1:09 pm Post subject: reference et NULL |
|
|
Bonjour,
J'ai toujours considéré qu'il fallait utiliser une référence (&) quand on
voulait garantir à une fonction qu'un paramètre ne pouvait pas être NULL :
void fct( Toto* t) // t peut être NULL, fct doit vérifier
void fct( Toto& t) // t est forcément valide
Hors, en faisant un test, le code suivant ne produit aucune erreur :
struct Toto { ... } ;
int main()
{
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution !
// si j'utilise t, maintenant, ca plantera ! mais ca ne plante pas à
l'affectation !
}
Donc je peux passer une référence invalide (NULL) à une fonction !
Ou bien mon raisonnement est faux et on a aucune garantie sur les references
?
(testé avec gcc 2.95)
|
|
| Back to top |
|
 |
Laurent Deniau Guest
|
Posted: Mon Jan 10, 2005 1:19 pm Post subject: Re: reference et NULL |
|
|
Amerio wrote:
| Quote: | Bonjour,
J'ai toujours considéré qu'il fallait utiliser une référence (&) quand on
voulait garantir à une fonction qu'un paramètre ne pouvait pas être NULL :
void fct( Toto* t) // t peut être NULL, fct doit vérifier
void fct( Toto& t) // t est forcément valide
Hors, en faisant un test, le code suivant ne produit aucune erreur :
struct Toto { ... } ;
int main()
{
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution !
// si j'utilise t, maintenant, ca plantera ! mais ca ne plante pas à
l'affectation !
}
Donc je peux passer une référence invalide (NULL) à une fonction !
Ou bien mon raisonnement est faux et on a aucune garantie sur les references
?
|
raisonnement faux (probablement sur la semantique de t = *t0).
a+, ld.
|
|
| Back to top |
|
 |
Marc Boyer Guest
|
Posted: Mon Jan 10, 2005 1:40 pm Post subject: Re: reference et NULL |
|
|
In article <41e27eb4$0$19589$636a15ce (AT) news (DOT) free.fr>, Amerio wrote:
| Quote: | Bonjour,
J'ai toujours considéré qu'il fallait utiliser une référence (&) quand on
voulait garantir à une fonction qu'un paramètre ne pouvait pas être NULL :
void fct( Toto* t) // t peut être NULL, fct doit vérifier
void fct( Toto& t) // t est forcément valide
Hors, en faisant un test, le code suivant ne produit aucune erreur :
struct Toto { ... } ;
int main()
{
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution !
|
Sauf qu'à partir du moment ou tu as écrit *t0, tu as provoqué
un Undefined behavior, donc ce qui se passe désormais peut-être
n'importe quoi.
Tu pourrais aussi écrire
memset(&t, 0, sizeof(Toto&) );
tu aurais surement le même ganre de comportement.
| Quote: | // si j'utilise t, maintenant, ca plantera ! mais ca ne plante pas à
l'affectation !
}
Donc je peux passer une référence invalide (NULL) à une fonction !
Ou bien mon raisonnement est faux et on a aucune garantie sur les references
?
(testé avec gcc 2.95)
|
Ton raisonnement a un biais. C'est comme les gens qui démontrent 1=2
en faisant une division par 0.
Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.
|
|
| Back to top |
|
 |
xavier Guest
|
Posted: Mon Jan 10, 2005 1:53 pm Post subject: Re: reference et NULL |
|
|
Amerio a dis le 10/01/2005 14:09:
| Quote: | t = *t0; // ca ne plante pas a l'execution !
|
Attention, cette instruction est équivalent à :
t.operator=(*t0);
Tu ne peux pas modifier l'espace mémoire "pointé" par une référence.
Il est toujours possible de créer une référence invalide, par exemple :
Toto & t = *(Toto *)0;
Mais il est impossible de manipuler une référence autrement qu'en la
déreferençant. C'est ce point qui fait la force d'une référence par
rapport à un pointeur. A partir du moment ou tu es sûr qu'une référence
a été correctement construite (i.e. qu'elle est valide), tu peux être
sûr que cette référence continuera d'être valide et qu'elle "pointera"
vers le même espace mémoire pendant toute sa vie.
// exemple.cpp
#include <iostream>
struct Toto {};
using namespace std;
int main() {
Toto t1;
cout << &t1 << endl;
Toto *t0 = 0;
Toto &t = t1;
cout << &t << endl;
t = *t0; // [1]
cout << &t << endl;
Toto & t2 = *(Toto*)0;
cout << &t2 << endl;
return 0;
}
//eof
$ g++ -o mtest exemple.cpp && ./mtest
0x22ff77
0x22ff77
0x22ff77
0
[1] Cette ligne ne provoque pas d'erreur à l'execution seulement parce
que la structure Toto est vide, et donc son operateur de copie par
défaut ne fait rien.
xavier
|
|
| Back to top |
|
 |
Amerio Guest
|
Posted: Mon Jan 10, 2005 2:39 pm Post subject: Re: reference et NULL |
|
|
xavier wrote:
| Quote: | Amerio a dis le 10/01/2005 14:09:
t = *t0; // ca ne plante pas a l'execution !
Attention, cette instruction est équivalent à :
t.operator=(*t0);
Tu ne peux pas modifier l'espace mémoire "pointé" par une référence.
|
Effectivement, je vois maintenant mon erreur !
Ca va tout de suite mieux quand on considere une reference comme un alias...
(on ne devrait donc pas comparer l'usage de Toto& à celui de Toto*, mais à
celui de Toto* const !)
Merci !
|
|
| Back to top |
|
 |
xavier Guest
|
Posted: Mon Jan 10, 2005 2:45 pm Post subject: Re: reference et NULL |
|
|
xavier a dis le 10/01/2005 14:53:
| Quote: | tu peux être sûr que cette référence continuera d'être valide et qu'elle "pointera"
vers le même espace mémoire pendant toute sa vie.
|
Ceci voulant dire également que le code suivant va poser problème :
Toto * p = new Toto;
Toto & t = *p;
delete p;
t.FaitQuelqueChose() ; // t "pointe" un espace mémoire libéré.
xavier
|
|
| Back to top |
|
 |
Marc Boyer Guest
|
Posted: Mon Jan 10, 2005 2:49 pm Post subject: Re: reference et NULL |
|
|
In article <41e28608$0$31781$626a14ce (AT) news (DOT) free.fr>, xavier wrote:
| Quote: | Amerio a dis le 10/01/2005 14:09:
t = *t0; // ca ne plante pas a l'execution !
Attention, cette instruction est équivalent à :
t.operator=(*t0);
Tu ne peux pas modifier l'espace mémoire "pointé" par une référence.
|
Si, on peut modifier l'objet désigné par une référence.
Ce qu'on ne doit pas pouvoir facilement faire, c'est changer
d'objet désigné (mais avec les placement new, je crois que
Gabriel m'avais montré que c'étais possible, mais ça devient
un usage un peu avancé pour moi).
#include <iostream>
using namespace std;
int main()
{
int i;
int &j= i;
j= 5;
cout<<"i ="<
}
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.
|
|
| Back to top |
|
 |
xavier Guest
|
Posted: Mon Jan 10, 2005 3:09 pm Post subject: Re: reference et NULL |
|
|
Marc Boyer a dis le 10/01/2005 15:49:
| Quote: | Tu ne peux pas modifier l'espace mémoire "pointé" par une référence.
Si, on peut modifier l'objet désigné par une référence.
|
Bien sûr, autant pour moi, ma formulation était vraiment malheureuse.
J'espère ne pas avoir apporté trop de confusion.
"On peut modifier la valeur de l'objet référencé, pas la référence
elle-même". Est-ce mieux? sachant que j'utilise déjà des guillemets
autour du très approximatif "pointé".
xavier
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Mon Jan 10, 2005 3:48 pm Post subject: Re: reference et NULL |
|
|
Marc Boyer wrote:
| Quote: | In article <41e27eb4$0$19589$636a15ce (AT) news (DOT) free.fr>, Amerio wrote:
J'ai toujours considéré qu'il fallait utiliser une référence
(&) quand on voulait garantir à une fonction qu'un paramètre
ne pouvait pas être NULL :
void fct( Toto* t) // t peut être NULL, fct doit vérifier
void fct( Toto& t) // t est forcément valide
Hors, en faisant un test, le code suivant ne produit aucune
erreur :
struct Toto { ... } ;
int main()
{
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution !
Sauf qu'à partir du moment ou tu as écrit *t0, tu as
provoqué un Undefined behavior, donc ce qui se passe désormais
peut-être n'importe quoi.
|
La question est, qu'est-ce qu'il essaie de montrer comme point.
Il commence en parlant de NULL, et qu'on ne peut pas avoir des
références nulle, mais son programme déréférence un pointeur
NULL, ce qui n'a rien à voir avec des références.
| Quote: | Tu pourrais aussi écrire
memset(&t, 0, sizeof(Toto&) );
tu aurais surement le même ganre de comportement.
|
Je le doute. Il n'y aurait de problème ici que si Toto a des
invariantes de classe qui sont violées en mettant tous ses
octets à zéro.
| Quote: | // si j'utilise t, maintenant, ca plantera ! mais ca ne
plante pas à l'affectation !
|
Chez moi, ça plante à l'affectation -- je ne peux même pas lire
à travers un pointeur nul. Mais c'est un comportement indéfini.
Il peut se passer n'importe quoi.
| Quote: | }
Donc je peux passer une référence invalide (NULL) à une
fonction !
|
Pas légalement. Mais je ne vois pas de rapport avec le code dans
l'exemple.
--
James Kanze GABI Software http://www.gabi-soft.fr
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
|
|
| Back to top |
|
 |
Marc Boyer Guest
|
Posted: Mon Jan 10, 2005 4:12 pm Post subject: Re: reference et NULL |
|
|
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
| Quote: | Marc Boyer wrote:
In article <41e27eb4$0$19589$636a15ce (AT) news (DOT) free.fr>, Amerio wrote:
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution !
[SNIP]
La question est, qu'est-ce qu'il essaie de montrer comme point.
Il commence en parlant de NULL, et qu'on ne peut pas avoir des
références nulle, mais son programme déréférence un pointeur
NULL, ce qui n'a rien à voir avec des références.
|
Oui et non.
Non dans le sens où ce sont des choses différentes.
Mais oui quand même dans le sens ou je ne serais pas
étonné qu'un compilateur représente en interne un pointeur
et une référence de la même manière, et qu'il optimise
une écriture du genre
Toto &t= *t;
en une copie interne de pointeur à pointeur.
| Quote: | Tu pourrais aussi écrire
memset(&t, 0, sizeof(Toto&) );
tu aurais surement le même ganre de comportement.
Je le doute. Il n'y aurait de problème ici que si Toto a des
invariantes de classe qui sont violées en mettant tous ses
octets à zéro.
|
Je pense que j'ai écris une grosse bétise sur ces lignes là.
Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.
|
|
| Back to top |
|
 |
Andre Heinen Guest
|
Posted: Mon Jan 10, 2005 4:31 pm Post subject: Re: reference et NULL |
|
|
On Mon, 10 Jan 2005 15:39:34 +0100, "Amerio" <amerio (AT) hotmail (DOT) com>
wrote:
| Quote: | Effectivement, je vois maintenant mon erreur !
Ca va tout de suite mieux quand on considere une reference comme un alias...
|
Oui.
| Quote: | (on ne devrait donc pas comparer l'usage de Toto& à celui de Toto*, mais à
celui de Toto* const !)
|
Je pense que tu aurais une meilleure idée de ce qu'est une
référence si tu la comparais non pas à un pointeur, mais un autre
nom pour une donnée. Par exemple:
int i;
int* p = &i;
int& r = i;
r est maintenant un autre nom pour i, et est beaucoup plus
similaire à i qu'à p.
--
André Heinen
Mon e-mail, encodé ROT13: n qbg urvara ng rhebcrnayvax qbg pbz
La FAQ: http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/
|
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Mon Jan 10, 2005 9:32 pm Post subject: Re: reference et NULL |
|
|
Marc Boyer wrote:
| Quote: | kanze (AT) gabi-soft (DOT) fr wrote:
Marc Boyer wrote:
In article <41e27eb4$0$19589$636a15ce (AT) news (DOT) free.fr>, Amerio wrote:
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution !
[SNIP]
La question est, qu'est-ce qu'il essaie de montrer comme
point. Il commence en parlant de NULL, et qu'on ne peut pas
avoir des références nulle, mais son programme déréférence un
pointeur NULL, ce qui n'a rien à voir avec des références.
Oui et non.
Non dans le sens où ce sont des choses différentes.
Mais oui quand même dans le sens ou je ne serais pas
étonné qu'un compilateur représente en interne un pointeur
et une référence de la même manière, et qu'il optimise
une écriture du genre
Toto &t= *t;
en une copie interne de pointeur à pointeur.
|
Ça dépend du contexte ; c'est une implémentation possible, même
s'il m'étonnerait un peu pour une variable locale.
Mais je ne vois toujours pas de rapport. Il n'y a pas de Toto &t
= *t dans son programme. Il y a un t qui est bien initialisé,
avec une variable locale. Et puis, on affecte ce t. C-à-d qu'on
affecte la variable locale avec lequel il a été initialisé.
Le problème dans son code n'est pas là. Le problem, c'est avec
le *t0 à droit de l'affectation. Et ça, c'est un problème avec
ou sans une référence à gauche ; t1 = *t0 pose autant de
problèmes.
--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
|
|
| Back to top |
|
 |
Marc Boyer Guest
|
Posted: Tue Jan 11, 2005 4:10 pm Post subject: Re: reference et NULL |
|
|
James Kanze wrote:
| Quote: | Marc Boyer wrote:
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Oui et non.
Non dans le sens où ce sont des choses différentes.
Mais oui quand même dans le sens ou je ne serais pas
étonné qu'un compilateur représente en interne un pointeur
et une référence de la même manière, et qu'il optimise
une écriture du genre
Toto &t= *t;
en une copie interne de pointeur à pointeur.
Ça dépend du contexte ; c'est une implémentation possible, même
s'il m'étonnerait un peu pour une variable locale.
|
Oui, en y réflechissant bien oui.
| Quote: | Mais je ne vois toujours pas de rapport. Il n'y a pas de Toto &t
= *t dans son programme. Il y a un t qui est bien initialisé,
avec une variable locale. Et puis, on affecte ce t. C-à-d qu'on
affecte la variable locale avec lequel il a été initialisé.
|
Tout à fait.
| Quote: | Le problème dans son code n'est pas là. Le problem, c'est avec
le *t0 à droit de l'affectation. Et ça, c'est un problème avec
ou sans une référence à gauche ; t1 = *t0 pose autant de
problèmes.
|
En fait, je me suis demandé pas mal s'il nous avait posté
exactement le code qu'il avait testé, car comme le tien,
mon compilateur plante dès l'affectation, pas après lors
de l'utilisation comme décrit par l'OP.
Mais comme les réponses données lui faisaient comprendre
son erreur conceptuelle, j'ai pas poussé dans le cas de
l'exemple donné.
Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.
|
|
| Back to top |
|
 |
Amerio Guest
|
Posted: Tue Jan 11, 2005 6:45 pm Post subject: Re: reference et NULL |
|
|
| Quote: | En fait, je me suis demandé pas mal s'il nous avait posté
exactement le code qu'il avait testé, car comme le tien,
mon compilateur plante dès l'affectation, pas après lors
de l'utilisation comme décrit par l'OP.
|
Oui le code que j'avais ecris etait exactement celui testé.
Pour rappel :
struct Toto {} ;
int main()
{
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution *chez moi*
}
| Quote: | Mais comme les réponses données lui faisaient comprendre
son erreur conceptuelle, j'ai pas poussé dans le cas de
l'exemple donné.
|
Tout a fait. En fait d'erreur de conception, ca fait parti de tests persos
que j'avais écris pour vérifier un truc sur les pointeurs, puis à force de
faire des trucs à droite à gauche pour comparer l'utilisation pointeur /
référence, j'ai dérivé jusqu'à "la chose" commise plus haut.
|
|
| Back to top |
|
 |
Marc Boyer Guest
|
Posted: Wed Jan 12, 2005 8:38 am Post subject: Re: reference et NULL |
|
|
In article <41e41ede$0$11970$636a15ce (AT) news (DOT) free.fr>, Amerio wrote:
| Quote: | En fait, je me suis demandé pas mal s'il nous avait posté
exactement le code qu'il avait testé, car comme le tien,
mon compilateur plante dès l'affectation, pas après lors
de l'utilisation comme décrit par l'OP.
Oui le code que j'avais ecris etait exactement celui testé.
Pour rappel :
struct Toto {} ;
int main()
{
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution *chez moi*
}
|
Ne serait-ce pas que, comme le compilo voit que t/t1 n'est
jamais utilisé, il ne fait pas cette opération ?
Que donne le code suivant:
#include <stdio>
struct Toto { int i; };
int main()
{
Toto t1;
Toto *t0 = 0;
Toto& t = t1; // ok tout va bien
t = *t0; // ca ne plante pas a l'execution *chez moi*
std:::cout<<"Affectation passee"<
t.i= 0;
std:::cout<<"Usage de t passe"<
}
Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|