OVH Cloud OVH Cloud

Appel d'une methode a partir d'un pointeur nul

28 réponses
Avatar
Olivier Miakinen
Bonjour,


Je voudrais savoir si ceci est légal :

class UneClasse
{
public:
void UneMethode();
/* plus d'autres méthodes */
}

void UneClasse::UneMethode()
{
if (this) {
/* faire des choses */
}
/* sinon ne rien faire */
}

et quelque part ailleurs :

UneClasse *uneInstance = NULL;
uneInstance->UneMethode();


Je viens de tomber sur un code qui fait quelque chose comme ça
(enfin... si je ne me suis pas trompé en recopiant et en changeant
les identifiants), et je me demande si cette façon d'appeler une
méthode en déréférençant un pointeur nul est portable. Je précise
que cela compile et s'exécute sans problème apparent avec Visual C++.


Cordialement,
--
Olivier Miakinen

10 réponses

1 2 3
Avatar
Alain Gaillard


void UneClasse::UneMethode()
{
if (this) {


Si je puis me permettre, ce test n'a aucun sens AMHA.


--
Alain

Avatar
Alain Gaillard


if (this)

par

assert (this);


AMHA toujours assert(this) n'a pas plus de sens que if(this)

--
Alain

Avatar
Sylvain
Alain Gaillard wrote on 09/09/2006 13:56:

void UneClasse::UneMethode(){
if (this) {


Si je puis me permettre, ce test n'a aucun sens AMHA.


partant du principe que l'on ne devrait jamais appeler une méthode
depuis un pointeur d'instance null, un tel appel peut être qualifié
d'erreur et ce test de non-sens.

parlant du traitement qu'en fait VC98, il donne un code fonctionnel (non
académique) mais viable (le "sens" du test étant de permettre des appels
'en aveugle')

if (pInstance) pInstance->foo();

se comportant comme:

rt CInstance::foo(){
if (this){
...
}
}
pInstance->foo();

je n'ai pas VC2005 sur cette machine, je pourrais regarder lundi, mais
je serais curieux de savoir comment d'autres compilo - dont gcc - se
comportent.

Sylvain.


Avatar
Alain Gaillard


quelle version ? quel mode d'exécution ? ...
98, 2003, 2005 plante une bombe pour l'accès à un pointeur null


Pas du tout, aussi incroyable que cela puisse paraître VC++ 98 et 2005
acceptent le code et ça fonctionne, même si la méthode est non statique.

Et le pire c'est que ça doit être légal car on déréférence un pointeur
null. La norme dit:

"Certain other operations are described in this International Standard
as undefined (for example, the effect of dereferencing
the null pointer)."

Le comportement est indéterminé donc ça à la droit de marcher.

Mais en fait si on prend cette exemple:

class UneClasse {
public:
void UneMethode(){ cout << "Hello" << endl;}
};

Tant que this ne sert pas, le corps de la méthode peut s'exécuteur comme
si elle était statique même si elle ne le l'est pas. Au pire this=NULL
est poussé sur la pile, mais comme il ne sert pas ....

Par contre si on prend:

class UneClasse {
public:
void UneMethode(){ value = 1;}
private:
int value;
};

Le plantage est garanti comme le veut le bon sens, mais. J'ai également
vérifié avec VC 98 et 2005

Quant à savoir si tester this dans un corps de méthode est une bonne
approche de la programmation C++, c'ets une autre histoire....

La morale de l'histoire est qu'un compilo n'utilise pas nécessairement
this pour construire un appel de méthode. Sans doute le but est d'éviter
une indirection dans un souci de performance.

--
Alain

Avatar
Alain Gaillard


partant du principe que l'on ne devrait jamais appeler une méthode
depuis un pointeur d'instance null, un tel appel peut être qualifié
d'erreur et ce test de non-sens.


Tu as déjà répondu à ce post que j'ai annulé juste après l'avoir posté.
J'en ai posté un autre pour essayer d'être plus clair.
Mais il n'en demeure pas moins que mon avis est que le test de this est
un non sens AMHA.

--
Alain

Avatar
Sylvain
Alain Gaillard wrote on 09/09/2006 14:25:

quelle version ? quel mode d'exécution ? ...
98, 2003, 2005 plante une bombe pour l'accès à un pointeur null


Pas du tout, aussi incroyable que cela puisse paraître VC++ 98 et 2005
acceptent le code et ça fonctionne, même si la méthode est non statique.


j'avais répondu un peu vite.

"Certain other operations are [..] undefined [...]


one more.

[...]
La morale de l'histoire est qu'un compilo n'utilise pas nécessairement
this pour construire un appel de méthode. Sans doute le but est d'éviter
une indirection dans un souci de performance.


tu l'as dit, il "sert" juste pour être pousser sur la pile.

si la méthode est virtuelle, this est accéder pour déteminer le saut --
l'adresse de la vtable pour la classe est stocké dans le bloc pointé par
l'instance dynamique (si c'est undefined, ça fait néanmoins sens).

Sylvain.


Avatar
Alain Gaillard

j'avais répondu un peu vite.


James ne va pas te rater. ;-) LOL

si la méthode est virtuelle, this est accéder pour déteminer le saut --
l'adresse de la vtable pour la classe est stocké dans le bloc pointé par
l'instance dynamique


Certes. Dans le cas d'une méthode virtuelle cela revient à lire
l'adresse 0 ce qui ne laissera pas l'OS indifférent...


--
Alain

Avatar
James Kanze
Olivier Miakinen wrote:

Je voudrais savoir si ceci est légal :

class UneClasse
{
public:
void UneMethode();
/* plus d'autres méthodes */
}

void UneClasse::UneMethode()
{
if (this) {
/* faire des choses */
}
/* sinon ne rien faire */
}

et quelque part ailleurs :

UneClasse *uneInstance = NULL;
uneInstance->UneMethode();


En aucun cas :

-- L'appel de la fonction (l'opérateur ->, en fait) compte bien
comme une déréférencement du pointeur (au moins que la
fonction soit statique). Dès ce moment, le compilateur peut
faire n'importe quoi. Et je me suis déjà servi d'un
compilateur qui en mode debug testait chaque déréférencement
(y compris dans un cas comme ceci), et abortait le programme
le cas échéant.

-- Étant donné l'impossibilité d'appeler la fonction avec un
pointeur null, n'importe quel compilateur digne de ce nom,
en mode optimisation, va ôter le test dans la fonction,
parce qu'il ne peut pas être faux.

Je viens de tomber sur un code qui fait quelque chose comme ça
(enfin... si je ne me suis pas trompé en recopiant et en
changeant les identifiants), et je me demande si cette façon
d'appeler une méthode en déréférençant un pointeur nul est
portable. Je précise que cela compile et s'exécute sans
problème apparent avec Visual C++.


Dans la mesure qu'il s'agit d'un comportement indéfini, un
compilateur n'est pas obligé à le faire échouer. Mais si ça
marche, c'est du pûr hazard, et au moins que Microsoft donne
d'autres garanties (une implémentation est en droit de définir
un comportement que la norme laisse indéfini), ça pourrait très
bien échouer avec une autre version du compilateur, voire même
avec d'autres options de compilation,

--
James Kanze (Gabi Software) email:
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

Avatar
James Kanze
Sylvain wrote:
Olivier Miakinen wrote on 08/09/2006 18:59:

class UneClasse {
public:
void UneMethode();
}
UneClasse *uneInstance = NULL;
uneInstance->UneMethode();

cela compile et s'exécute sans problème apparent avec Visual
C++.


quelle version ? quel mode d'exécution ? ...
98, 2003, 2005 plante une bombe pour l'accès à un pointeur null

... sauf pour 98 si la méthode est statique, c'est ici une
erreur du compilo qui accepte le "uneInstance->" ou
"uneInstance." alors que seul "UneClasse::" devrait être
valide.


La syntaxe reste valide, et c'est parfaitement acceptable
d'appeler une fonction statique avec la notation obj.f() ou
ptr->f(). En revanche, la norme dit que même dans ce cas-ci,
l'expression à droit du . (c-à-d (*ptr) dans le cas de ->) est
évaluée. Et donc, un pointeur nul donne un comportement
indéfini.

Je ne suis pas sûr, mais je crois que la décision qu'il faut
évaluer l'expression, même si la fonction est statique, a été
prise assez tardivement. En tout cas, l'ARM ne le précisait pas.
Et c'est donc possible que des compilateurs plutôt anciens (VC++
6.0, par exemple) ne l'implémentent pas.

--
James Kanze (Gabi Software) email:
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


Avatar
James Kanze
Alain Gaillard wrote:

quelle version ? quel mode d'exécution ? ... 98, 2003, 2005
plante une bombe pour l'accès à un pointeur null


Pas du tout, aussi incroyable que cela puisse paraître VC++ 98
et 2005 acceptent le code et ça fonctionne, même si la méthode
est non statique.

Et le pire c'est que ça doit être légal car on déréférence un
pointeur null. La norme dit:

"Certain other operations are described in this International
Standard as undefined (for example, the effect of
dereferencing the null pointer)."


Tout à fait. La syntaxe est légale, que la fonction soit
statique ou non.

Ce qui n'est pas si évident, c'est que dans le cas d'une
fonction statique, la norme exige quand même que l'expression à
gauche soit évaluée. Ce qui signifie que même avec une fonction
statique, tu as un comportement indéfini.

Le comportement est indéterminé donc ça à la droit de marcher.

Mais en fait si on prend cette exemple:

class UneClasse {
public:
void UneMethode(){ cout << "Hello" << endl;}
};

Tant que this ne sert pas, le corps de la méthode peut
s'exécuteur comme si elle était statique même si elle ne le
l'est pas. Au pire this=NULL est poussé sur la pile, mais
comme il ne sert pas ....


C'est le comportement « par défaut » de beaucoup de
compilateurs, j'imagine.

Par contre si on prend:

class UneClasse {
public:
void UneMethode(){ value = 1;}
private:
int value;
};

Le plantage est garanti comme le veut le bon sens, mais. J'ai
également vérifié avec VC 98 et 2005

Quant à savoir si tester this dans un corps de méthode est une
bonne approche de la programmation C++, c'ets une autre
histoire....


La risque réele, c'est que ça fonctionne en mode débogue, mais
pas une fois qu'on active l'optimisation. Le compilateur note
que le test ne peut pas échouer, et le supprime.

La morale de l'histoire est qu'un compilo n'utilise pas
nécessairement this pour construire un appel de méthode. Sans
doute le but est d'éviter une indirection dans un souci de
performance.


Tout à fait.

--
James Kanze (Gabi Software) email:
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


1 2 3