Les deux (a)
et (b)
entraînent un comportement indéfini. L'appel d'une fonction membre via un pointeur nul est toujours un comportement indéfini. Si la fonction est statique, elle est techniquement indéfinie également, mais il y a un différend.
La première chose à comprendre est pourquoi il est un comportement non défini de déréférencer un pointeur nul. En C ++ 03, il y a en fait un peu d'ambiguïté ici.
Bien que "déréférencer un pointeur nul entraîne un comportement indéfini" est mentionné dans les notes du §1.9 / 4 et du §8.3.2 / 4, il n'est jamais explicitement indiqué. (Les notes ne sont pas normatives.)
Cependant, on peut essayer de le déduire du §3.10 / 2:
Une lvalue fait référence à un objet ou à une fonction.
Lors du déréférencement, le résultat est une lvalue. Un pointeur nul ne fait pas référence à un objet, par conséquent, lorsque nous utilisons la valeur l, nous avons un comportement indéfini. Le problème est que la phrase précédente n'est jamais énoncée, alors que signifie "utiliser" la lvalue? Le générer même pas du tout, ou l'utiliser dans le sens plus formel de la conversion d'une valeur à une valeur?
Quoi qu'il en soit, il ne peut certainement pas être converti en une valeur r (§4.1 / 1):
Si l'objet auquel se réfère la valeur l n'est pas un objet de type T et n'est pas un objet d'un type dérivé de T, ou si l'objet n'est pas initialisé, un programme qui nécessite cette conversion a un comportement indéfini.
Ici, c'est définitivement un comportement indéfini.
L'ambiguïté vient du fait qu'il s'agit ou non d'un comportement indéfini de déférence mais pas d'utiliser la valeur d'un pointeur invalide (c'est-à-dire obtenir une lvalue mais pas la convertir en une rvalue). Sinon, alors int *i = 0; *i; &(*i);
est bien défini. C'est un problème actif .
Nous avons donc une vue stricte «déréférencer un pointeur nul, obtenir un comportement indéfini» et une vue faible «utiliser un pointeur nul déréférencé, obtenir un comportement indéfini».
Maintenant, nous considérons la question.
Oui, (a)
entraîne un comportement indéfini. En fait, si this
est nul, alors quel que soit le contenu de la fonction, le résultat n'est pas défini.
Cela découle du §5.2.5 / 3:
Si E1
a le type «pointeur vers la classe X», alors l'expression E1->E2
est convertie dans la forme équivalente(*(E1)).E2;
*(E1)
entraînera un comportement indéfini avec une interprétation stricte, et le .E2
convertit en une rvalue, ce qui en fait un comportement indéfini pour l'interprétation faible.
Il s'ensuit également que c'est un comportement indéfini directement à partir du (§9.3.1 / 1):
Si une fonction membre non statique d'une classe X est appelée pour un objet qui n'est pas de type X ou d'un type dérivé de X, le comportement n'est pas défini.
Avec les fonctions statiques, l'interprétation stricte ou faible fait la différence. Strictement parlant, il n'est pas défini:
Un membre statique peut être référencé en utilisant la syntaxe d'accès aux membres de classe, auquel cas l'expression objet est évaluée.
Autrement dit, il est évalué comme s'il était non statique et nous déréférencerons à nouveau un pointeur nul avec (*(E1)).E2
.
Cependant, comme il E1
n'est pas utilisé dans un appel de fonction membre statique, si nous utilisons l'interprétation faible, l'appel est bien défini. *(E1)
entraîne une valeur l, la fonction statique est résolue, *(E1)
est rejetée et la fonction est appelée. Il n'y a pas de conversion lvalue-en-rvalue, donc il n'y a pas de comportement indéfini.
En C ++ 0x, à partir de n3126, l'ambiguïté demeure. Pour l'instant, soyez prudent: utilisez l'interprétation stricte.