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?


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;


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.


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.


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.


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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.