Como a inicialização do valor “int * ptr = int ()” não é ilegal?

86

O seguinte código (retirado daqui ):

int* ptr = int();

compila no Visual C ++ e inicializa o valor do ponteiro.

Como isso é possível? Quer dizer, int()produz um objeto do tipo inte não posso atribuir um inta um ponteiro.

Como o código acima não é ilegal?

dente afiado
fonte
Não é uma resposta, mas ótima pergunta! Eu nunca vi tal coisa.
Josh
6
Como os primitivos têm um 'construtor' em C ++, int()produz o valor do valor construído int(que eu acho que é uma coisa especificada em C ++ 03) e o valor padrão inté 0. Isso é equivalente aint *ptr = 0;
wkl
7
@EmanuelEy: Não, qualquer constante inteira com valor zero pode ser usada como uma constante de ponteiro nulo, independentemente de como os ponteiros são realmente implementados.
Mike Seymour
1
@MooingDuck: Eu não disse que NULLpoderia ser um valor diferente de zero. Eu disse que poderia ser qualquer constante inteira de valor zero (que inclui int()).
Mike Seymour
5
@DanielPryden Esse é um uso da palavra "objeto" que eu desconhecia anteriormente.
fofo

Respostas:

110

int()é uma expressão constante com valor 0, portanto, é uma forma válida de produzir uma constante de ponteiro nulo. Em última análise, é apenas uma maneira ligeiramente diferente de dizerint *ptr = NULL;

Jerry Coffin
fonte
3
+1, o bit de expressão constante é importante e ausente nas 2 primeiras respostas votadas.
David Rodríguez - dribeas
isso vai embora com C ++ 0x?
Neil G
@ NeilG: Isso permanece o mesmo no C ++ 11, embora agora haja também um nullptr, que você pode usar em vez de 0ou NULLem um novo código.
Jerry Coffin
2
@Nils: clareza de código e declaração de sua intenção por meio de código. Claro, com C ++ 11, agora você deseja usar nullptr porque ele também lança o benefício de verificações extras de tempo de compilação na mistura.
Jamin Gray
3
@Nils porque obviamente 0pode significar uma constante de ponteiro nula ou o número 0, enquanto nullptré óbvio uma constante de ponteiro nula. Além disso, como disse Jamin, ele também tem "verificações extras de tempo de compilação". Tente pensar antes de digitar.
Miles Rout
35

Porque int()rende 0, que é intercambiável com NULL. NULLem si é definido como 0, ao contrário de C, NULLque é (void *) 0.

Observe que isso seria um erro:

int* ptr = int(5);

e isso ainda funcionará:

int* ptr = int(0);

0é um valor constante especial e, como tal, pode ser tratado como um valor de ponteiro. Expressões constantes que produzem 0, como 1 - 1são também permitidas como constantes de ponteiro nulo.

Blagovest Buyukliev
fonte
1
Observe também que C's NULL também não é necessariamente (void *)0. É simplesmente uma "expressão constante de número inteiro definida pela implementação com o valor 0 ou tal expressão convertida para o tipo void *".
Jerry Coffin
@JerryCoffin Eu nunca usei um compilador C que define NULLcomo (void*)0; sempre foi 0(ou talvez 0L). (Mas então, quando C90 se tornou (void*)0legal em C, eu já estava usando C ++.)
James Kanze
1
@JamesKanze: No ubuntu 11.04 e em nosso próprio sabor do Linux, libio.h contém: #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)a versão atual do gcc no ubuntu é 4.5, em nosso sistema é 4.0.
David Rodríguez - dribeas
5
" 0é um literal especial" - apenas porque é uma expressão constante e tem o valor especial 0. (1-1)é igualmente especial, também é uma constante de ponteiro nulo e assim é int(). O fato de 0ser literal é condição suficiente, mas não necessária, para ser uma expressão constante. Algo como strlen(""), embora também tenha o valor especial 0, não é uma expressão constante e, portanto, não é uma constante de ponteiro nulo.
Steve Jessop
@SteveJessop: Eu concordo com a correção, é realmente sobre o valor constante 0, não o 0literal.
Blagovest Buyukliev
18

A expressão é int()avaliada como um inteiro inicializado por padrão constante, que é o valor 0. Esse valor é especial: ele é usado para inicializar um ponteiro para o estado NULL.

Mark Ransom
fonte
2
Falta a isso um detalhe muito importante presente na resposta de Jerry: não basta que a expressão forneça o valor 0, mas também deve ser uma expressão constante . Para um contra-exemplo, com int f() { return 0; }, a expressão f()produz o valor 0, mas não pode ser usada para inicializar um ponteiro.
David Rodríguez - dribeas
@DavidRodríguez-dribeas, na minha pressa em apresentar uma resposta nos termos mais simples possíveis, deixei de fora essa parte. Espero que seja aceitável agora.
Mark Ransom
13

De n3290 (C ++ 03 usa texto semelhante), 4.10 Conversões de ponteiro [conv.ptr] parágrafo 1 (a ênfase é minha):

1 Uma constante de ponteiro nulo é uma expressão de constante integral (5.19) prvalue do tipo inteiro que avalia para zero ou um prvalue do tipo std :: nullptr_t. Uma constante de ponteiro nulo pode ser convertida em um tipo de ponteiro; o resultado é o valor de ponteiro nulo desse tipo e é distinguível de qualquer outro valor de ponteiro de objeto ou tipo de ponteiro de função. Essa conversão é chamada de conversão de ponteiro nulo. [...]

int()é uma expressão constante integral prvalue do tipo inteiro que avalia como zero (isso é demais!) e, portanto, pode ser usada para inicializar um tipo de ponteiro. Como você pode ver, 0não é a única expressão integral com caixa especial.

Luc Danton
fonte
4

Bem, int não é um objeto.

Eu acredito que o que está acontecendo aqui é que você está dizendo ao int * para apontar para algum endereço de memória determinado por int ()

então, se int () criar 0, int * apontará para o endereço de memória 0

Megatron
fonte
1
int()com certeza é um objeto.
Lightness Races in Orbit
@Tomalak: Acho que não. É um tipo temporário de não classe, e acho que estou certo em dizer que esses não são objetos no que diz respeito ao padrão C ++. É um pouco estranho, entretanto, a seção sobre "objetos temporários" começa falando cuidadosamente apenas sobre temporários do tipo de classe, mas depois fala sobre referências de ligação e, claro, você pode ligar uma referência a int(). Definir int i;, então sem dúvida, ié um objeto.
Steve Jessop
@Steve: Eu esperava um debate sobre isso porque os "objetos" são uma região de armazenamento em C ++ e os temporários realmente não têm armazenamento, certo? 1.8 / 1 não lista explicitamente os temporários, mas parece que existe a intenção de incluí-los.
Lightness Races in Orbit
1
@Tomalak: sim, de fato, temporários de tipo não-classe não precisam de armazenamento a menos que você pegue uma referência. Não importa, não importa muito. A afirmação "bem, não é um objeto" só é verdadeira porque inté um tipo, não um objeto. Se int()produz um objeto ou apenas um rvalue, não afeta nada que alguém tenha dito em outro lugar.
Steve Jessop
@Steve: Isso é indiscutível :)
Lightness Races in Orbit