Comment l'initialisation de la valeur «int * ptr = int ()» n'est-elle pas illégale?

86

Le code suivant (tiré d'ici ):

int* ptr = int();

compile en Visual C ++ et initialise la valeur du pointeur.

Comment est-ce possible? Je veux dire int()donne un objet de type intet je ne peux pas attribuer un intà un pointeur.

En quoi le code ci-dessus n'est-il pas illégal?

dents acérées
la source
Pas une réponse, mais une excellente question! Je n'ai jamais vu une chose pareille.
Josh
6
Puisque les primitives ont un «constructeur» en C ++, int()la valeur construite est la valeur de int(qui est, je pense, une chose spécifiée par C ++ 03) et la valeur par défaut de intest 0. Cela équivaut àint *ptr = 0;
sem
7
@EmanuelEy: Non, toute constante entière de valeur zéro peut être utilisée comme constante de pointeur nul, quelle que soit la manière dont les pointeurs sont réellement implémentés.
Mike Seymour
1
@MooingDuck: Je n'ai pas dit que NULLpourrait être une valeur non nulle. J'ai dit que cela pouvait être n'importe quelle constante entière de valeur zéro (qui comprend int()).
Mike Seymour
5
@DanielPryden C'est une utilisation du mot "objet" dont j'ignorais auparavant.
moelleux

Réponses:

110

int()est une expression constante avec une valeur de 0, c'est donc un moyen valide de produire une constante de pointeur nul. En fin de compte, c'est juste une manière légèrement différente de direint *ptr = NULL;

Jerry Coffin
la source
3
+1, le bit d' expression constante est important et absent des 2 premières réponses positives.
David Rodríguez - dribeas
cela disparaît-il avec C ++ 0x?
Neil G
@NeilG: Cela reste le même en C ++ 11, bien qu'il y ait maintenant aussi un nullptr, que vous pouvez utiliser à la place 0ou NULLdans un nouveau code.
Jerry Coffin
2
@Nils: Clarté du code et déclaration de votre intention par le biais du code. Bien sûr, avec C ++ 11, vous voulez maintenant utiliser nullptr car il jette également l'avantage de vérifications supplémentaires au moment de la compilation dans le mix.
Jamin Gray
3
@Nils car cela 0peut évidemment signifier une constante de pointeur nul ou le nombre 0, alors que nullptrc'est évident une constante de pointeur nul. De plus, comme Jamin l'a dit, il dispose également de "contrôles supplémentaires à la compilation". Essayez de réfléchir avant de taper.
Miles Rout
35

Parce que les int()rendements 0, qui sont interchangeables avec NULL. NULLlui-même est défini comme 0, contrairement à C NULLqui est (void *) 0.

Notez que ce serait une erreur:

int* ptr = int(5);

et cela fonctionnera toujours:

int* ptr = int(0);

0est une valeur constante spéciale et en tant que telle, elle peut être traitée comme une valeur de pointeur. Expressions constantes qui produisent 0, telles que les 1 - 1constantes de pointeur nul.

Blagovest Buyukliev
la source
1
Notez également que NULL de C n'est pas nécessairement non (void *)0plus. C'est simplement une implémentation définie "expression constante entière avec la valeur 0, ou une telle expression convertie en type void *".
Jerry Coffin
@JerryCoffin Je n'ai jamais utilisé de compilateur C défini NULLcomme (void*)0; c'était toujours 0(ou peut-être 0L). (Mais ensuite, au moment où C90 a été (void*)0légalisé en C, j'utilisais déjà C ++.)
James Kanze
1
@JamesKanze: Dans ubuntu 11.04 et notre propre saveur Linux, libio.h contient: #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)la version actuelle de gcc dans ubuntu est 4.5, dans notre système est 4.0.
David Rodríguez - dribeas
5
" 0est un littéral spécial" - uniquement parce que c'est une expression constante et qu'il a la valeur spéciale 0. (1-1)est tout aussi spécial, c'est aussi une constante de pointeur nul, et il en est de même int(). Le fait d' 0être un littéral est une condition suffisante mais non nécessaire pour être une expression constante. Quelque chose comme strlen(""), bien qu'il ait également la valeur spéciale 0, n'est pas une expression constante et n'est donc pas une constante de pointeur nul.
Steve Jessop
@SteveJessop: Je suis d'accord sur la correction, c'est vraiment la valeur constante 0, pas le 0littéral.
Blagovest Buyukliev
18

L'expression est int()évaluée à un entier constant initialisé par défaut, qui est la valeur 0. Cette valeur est spéciale: elle est utilisée pour initialiser un pointeur vers l'état NULL.

Mark Ransom
la source
2
Il manque un détail très important présent dans la réponse de Jerry: il ne suffit pas que l'expression donne la valeur 0, mais ce doit aussi être une expression constante . Pour un contre-exemple, avec int f() { return 0; }, l'expression f()renvoie la valeur 0, mais elle ne peut pas être utilisée pour initialiser un pointeur.
David Rodríguez - dribeas
@ DavidRodríguez-dribeas, dans mon empressement à présenter une réponse dans les termes les plus simples possibles, j'ai laissé cette partie de côté. J'espère que c'est acceptable maintenant.
Mark Ransom
13

À partir de n3290 (C ++ 03 utilise un texte similaire), 4.10 Conversions de pointeur [conv.ptr] paragraphe 1 (l'accent est mis sur moi):

1 Une constante de pointeur nul est une expression constante intégrale (5.19) prvalue de type entier qui prend la valeur zéro ou une prvalue de type std :: nullptr_t. Une constante de pointeur nul peut être convertie en un type de pointeur; le résultat est la valeur de pointeur nul de ce type et se distingue de toutes les autres valeurs de type pointeur d'objet ou pointeur de fonction. Une telle conversion est appelée une conversion de pointeur nul. [...]

int()est une telle expression constante intégrale prvalue de type entier qui évalue à zéro (c'est une bouchée!), et peut donc être utilisée pour initialiser un type de pointeur. Comme vous pouvez le voir, ce 0n'est pas la seule expression intégrale à casse spéciale.

Luc Danton
la source
4

Eh bien, int n'est pas un objet.

Je crois que ce qui se passe ici, c'est que vous dites à l'int * de pointer vers une adresse mémoire déterminée par int ()

donc si int () crée 0, int * pointera vers l'adresse mémoire 0

Megatron
la source
1
int()est certainement un objet.
Courses de légèreté en orbite
@Tomalak: Je ne pense pas que ce soit le cas. C'est un type temporaire de non-classe, et je pense avoir raison de dire que ce ne sont pas des objets en ce qui concerne la norme C ++. C'est un peu étrange, cependant, la section sur les "objets temporaires" commence par ne parler que des temporaires de type classe, mais plus tard, elle parle des références de liaison, et bien sûr vous pouvez lier une référence à int(). Définir int i;, alors pas de question, iest un objet.
Steve Jessop
@Steve: Je m'attendrais seulement à un débat à ce sujet dans la mesure où les "objets" sont une région de stockage en C ++, et les temporaires n'ont pas vraiment de stockage, non? 1.8 / 1 ne répertorie pas explicitement les temporaires, mais il semble que l'intention est là pour les inclure.
Courses de légèreté en orbite
1
@Tomalak: oui en effet, les temporaires de type non-classe n'ont pas besoin de stockage sauf si vous prenez une référence. Qu'à cela ne tienne, cela n'a pas beaucoup d'importance. L'instruction "well int n'est pas un objet" n'est vraie que parce que intc'est un type, pas un objet. Que ce soit int()un objet ou juste une rvalue n'affecte rien de ce que quelqu'un a dit ailleurs.
Steve Jessop
@Steve: C'est indiscutable :)
Courses de légèreté en orbite