 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
ByB Guest
|
Posted: Tue Apr 25, 2006 8:07 pm Post subject: surprise (this = 0) |
|
|
J'ai été plutôt surpris de constater que :
class Toto
{
// SNIP constructeurs et destructeurs supposés corrects
public :
int titi;
void Affiche()
{
MessageBox(0,"COUCOU","COUCOU",MB_OK);
}
void Affiche2()
{
titi = 1;
MessageBox(0,"COUCOU","COUCOU",MB_OK);
}
}
main
{
Toto *t = 0;
t->Affiche(); // cela fonctionne !
t->Affiche2(); // cela "plante"
}
Que l'appel de Affiche2() fasse planter, je comprends, car
l'utilisation de titi est équivalente ) l'utilisation de this->titi, et
ici, this = 0 (si j'ai bien compris).
Mais je suis plutôt surpris que t->Affiche() marche sans problèmes, du
moins avec le compilateur Visual C++ 6.0 de Microsoft ...
Comment cela s'explique t-il ?
PS : Je sais que MessageBox() n'est pas une fonction C++ standard, mais
c'est juste un exemple, tiré d'un programme développé sous Windows ...
--
Il y a un seul cas où il est convenable d'aborder une femme laide.
C'est pour lui demander si elle ne connaît pas l'adresse d'une jolie
femme.
[Pierre Desproges] |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Tue Apr 25, 2006 9:06 pm Post subject: Re: surprise (this = 0) |
|
|
ByB wrote:
| Quote: | J'ai été plutôt surpris de constater que :
class Toto
{
// SNIP constructeurs et destructeurs supposés corrects
public :
int titi;
void Affiche()
{
MessageBox(0,"COUCOU","COUCOU",MB_OK);
}
void Affiche2()
{
titi = 1;
MessageBox(0,"COUCOU","COUCOU",MB_OK);
}
}
main
{
Toto *t = 0;
t->Affiche(); // cela fonctionne !
t->Affiche2(); // cela "plante"
}
Que l'appel de Affiche2() fasse planter, je comprends, car
l'utilisation de titi est équivalente ) l'utilisation de
this->titi, et ici, this = 0 (si j'ai bien compris).
|
À peu près. Ce que tu décris, c'est sans doute ce qui se passe
avec ton implémentation -- et j'imagine ça serait pareil avec
beaucoup d'autres implémentations. Mais du point de vue du
langage, c'est un comportement indéfini, et je me suis déjà
servi d'une implémentation où ça n'aurait pas provoqué une
erreur évidente.
| Quote: | Mais je suis plutôt surpris que t->Affiche() marche sans
problèmes, du moins avec le compilateur Visual C++ 6.0 de
Microsoft ... Comment cela s'explique t-il ?
|
Que c'est un comportement indéfini, et que parfois, ça peut
donner l'impression de fonctionner. Ici, c'est probable que le
code généré ne se sert jamais du pointeur this -- donc, le fait
qu'il ait une valeur loufoque passe inaperçu.
Je me suis aussi servi une fois d'une compilateur où les deux
appels auraient provoqué une erreur. Au point de l'appel, sans
jamais entrer dans la fonction.
| Quote: | PS : Je sais que MessageBox() n'est pas une fonction C++
standard, mais c'est juste un exemple, tiré d'un programme
développé sous Windows ...
|
La question, c'est est-ce qu'il se sert de quelque chose dans
Toto, pour que le compilateur ait besoin d'utiliser le pointeur
this qu'on a passé à la fonction. Apparamment, non, et donc,
Affiche a l'air de marcher.
--
James Kanze kanze.james (AT) neuf (DOT) 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 |
|
 |
Aurelien Regat-Barrel Guest
|
Posted: Wed Apr 26, 2006 8:06 am Post subject: Re: surprise (this = 0) |
|
|
ByB a écrit :
| Quote: | J'ai été plutôt surpris de constater que :
class Toto
{
// SNIP constructeurs et destructeurs supposés corrects
public :
int titi;
void Affiche()
{
MessageBox(0,"COUCOU","COUCOU",MB_OK);
}
void Affiche2()
{
titi = 1;
MessageBox(0,"COUCOU","COUCOU",MB_OK);
}
}
main
{
Toto *t = 0;
t->Affiche(); // cela fonctionne !
t->Affiche2(); // cela "plante"
}
|
Tu as essayé:
int i = 0;
Toto *t = reinterpret_cast<Toto*>( &i );
t->Affiche2();
cout << i;
:-)
--
Aurélien Regat-Barrel |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Thu Apr 27, 2006 7:06 am Post subject: Re: surprise (this = 0) |
|
|
Aurelien Regat-Barrel wrote:
| Quote: | ByB a écrit :
J'ai été plutôt surpris de constater que :
|
[Exemple de comportement indéfini coupé...]
| Quote: | Tu as essayé:
int i = 0;
Toto *t = reinterpret_cast<Toto*>( &i );
t->Affiche2();
cout << i;
:-)
|
Ce qui doit faire quoi ?
Sur deux de mes machines (Sun Sparc, PC avec AMD 64 Bits), un
pointeur a 8 octets, et un int 4 -- on récupère donc quatre
octets avec des valeurs aléatoire dans t.
Note aussi qu'il y a eu des architectures (plusieurs, même) où
un pointeur null n'avait pas tous les bits à zéro ; où même si
int et char* avait la même taille, t n'aurait pas une valeur de
pointeur null après ta manip.
--
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 |
|
| Back to top |
|
 |
Aurelien Regat-Barrel Guest
|
Posted: Thu Apr 27, 2006 10:06 am Post subject: Re: surprise (this = 0) |
|
|
kanze a écrit :
| Quote: | Tu as essayé:
int i = 0;
Toto *t = reinterpret_cast<Toto*>( &i );
t->Affiche2();
cout << i;
:-)
Ce qui doit faire quoi ?
Sur deux de mes machines (Sun Sparc, PC avec AMD 64 Bits), un
pointeur a 8 octets, et un int 4 -- on récupère donc quatre
octets avec des valeurs aléatoire dans t.
|
Je ne sais pas si tu as noté le &i et non i tout seul => je cherche à ce
que t == &i, donc que t->titi == i ; Toto étant définie ainsi:
class Toto {
public:
int titi;
void Affiche2() { titi = 1; }
};
J'ai testé vite fait (VC++), ça affiche 1.
| Quote: | Note aussi qu'il y a eu des architectures (plusieurs, même) où
un pointeur null n'avait pas tous les bits à zéro ; où même si
int et char* avait la même taille, t n'aurait pas une valeur de
pointeur null après ta manip.
|
--
Aurélien Regat-Barrel |
|
| Back to top |
|
 |
Sylvain Guest
|
Posted: Thu Apr 27, 2006 1:06 pm Post subject: Re: surprise (this = 0) |
|
|
Aurelien Regat-Barrel wrote on 27/04/2006 11:34:
| Quote: |
Je ne sais pas si tu as noté le &i et non i tout seul => je cherche à ce
que t == &i, donc que t->titi == i ; Toto étant définie ainsi:
|
on avait compris que tu espérais en effet mapper la data membre titi sur
la pile de l'appellant:
- cela est très compilo dépendant,
- cela dépend de la convention d'appel,
- cela implique des présupposés sur la classe
au mieux tu mets en évidence un bug qui pourrait pas ne pas détecté du
premier coup.
Sylvain. |
|
| Back to top |
|
 |
Aurelien Regat-Barrel Guest
|
Posted: Thu Apr 27, 2006 3:06 pm Post subject: Re: surprise (this = 0) |
|
|
Sylvain a écrit :
| Quote: | Aurelien Regat-Barrel wrote on 27/04/2006 11:34:
Je ne sais pas si tu as noté le &i et non i tout seul => je cherche à
ce que t == &i, donc que t->titi == i ; Toto étant définie ainsi:
on avait compris que tu espérais en effet mapper la data membre titi sur
la pile de l'appellant:
- cela est très compilo dépendant,
- cela dépend de la convention d'appel,
- cela implique des présupposés sur la classe
au mieux tu mets en évidence un bug qui pourrait pas ne pas détecté du
premier coup.
|
Oui biensûr c'est pas quelque chose à utiliser, c'était juste un
exemple. Celà dit, pour un cas aussi simple, ça me semble pas si
aléatoire que cela (la convention d'appel est normalisée il me semble,
Toto n'a pas de vtable, ...).
Tu as un exemple en tête ?
--
Aurélien Regat-Barrel |
|
| Back to top |
|
 |
Sylvain Guest
|
Posted: Thu Apr 27, 2006 3:06 pm Post subject: Re: surprise (this = 0) |
|
|
Aurelien Regat-Barrel wrote on 27/04/2006 16:07:
| Quote: |
Tu as un exemple en tête ?
|
pas contredisant ton exemple dans sa simplicté (pas de vtable, etc).
je voulais juste souligner que ça peut donner l'impression de marcher
dans un cas très simple mais que cela résulte d'un effet de bord plus
génant (non détection de bug) qu'utile.
Sylvain. |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Thu Apr 27, 2006 5:06 pm Post subject: Re: surprise (this = 0) |
|
|
Aurelien Regat-Barrel wrote:
| Quote: | kanze a écrit :
Tu as essayé:
int i = 0;
Toto *t = reinterpret_cast<Toto*>( &i );
t->Affiche2();
cout << i;
:-)
Ce qui doit faire quoi ?
Sur deux de mes machines (Sun Sparc, PC avec AMD 64 Bits),
un pointeur a 8 octets, et un int 4 -- on récupère donc
quatre octets avec des valeurs aléatoire dans t.
Je ne sais pas si tu as noté le &i et non i tout seul => je
cherche à ce que t == &i, donc que t->titi == i ; Toto étant
définie ainsi:
class Toto {
public:
int titi;
void Affiche2() { titi = 1; }
};
J'ai testé vite fait (VC++), ça affiche 1.
|
OK. J'avais effectivement râté un & quelque part.
Maintenant, ajoute une fonction virtualle et voir ce qui se
passe. Dans la mesure où la classe n'est pas un POD, tu n'as pas
de garantie.
Mais je n'avais pas vu le smiley non plus. Alors, je suppose que
ton propos était plutôt de montre jusqu'où on peut aller, et que
ça donne encore l'impression de marcher. (Si tu veux vraiment
voir jusqu'où on peut aller avec le comportement indéfini qui
marche, il y a un exemple dans Coplien où il change le vptr,
pour qu'une instance d'une classe se comporte comme une 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 |
|
| 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
|
|