Agora temos o C ++ 11 com muitos novos recursos. Um interessante e confuso (pelo menos para mim) é o novo nullptr
.
Bem, não há mais necessidade da macro desagradável NULL
.
int* x = nullptr;
myclass* obj = nullptr;
Ainda assim, não estou entendendo como nullptr
funciona. Por exemplo, o artigo da Wikipedia diz:
O C ++ 11 corrige isso introduzindo uma nova palavra - chave para servir como uma constante distinta de ponteiro nulo: nullptr. É do tipo nullptr_t , implicitamente conversível e comparável a qualquer tipo de ponteiro ou tipo de ponteiro para membro. Não é implicitamente conversível ou comparável a tipos integrais, exceto bool.
Como é uma palavra-chave e uma instância de um tipo?
Além disso, você tem outro exemplo (além do da Wikipedia) em que nullptr
é superior ao bom e velho 0
?
nullptr
também é usado para representar referência nula para identificadores gerenciados em C ++ / CLI.nullptr_t
garantido ter apenas um membronullptr
? Portanto, se uma função retornounullptr_t
, o compilador já sabe qual valor será retornado, independentemente do corpo da função?std::nullptr_t
pode ser instanciado, mas todas as instâncias serão idênticasnullptr
porque o tipo é definido comotypedef decltype(nullptr) nullptr_t
. Eu acredito que a principal razão pela qual o tipo existe é para que as funções possam ser sobrecarregadas especificamente para capturanullptr
, se necessário. Veja aqui um exemplo.Respostas:
Isso não é surpreendente. Ambos
true
efalse
são palavras-chave e como literais eles têm um tipo (bool
).nullptr
é um ponteiro literal do tipostd::nullptr_t
e é um pré-valor (você não pode usar o endereço dele&
).4.10
sobre a conversão de ponteiro diz que um pré-valor do tipostd::nullptr_t
é uma constante de ponteiro nulo e que uma constante de ponteiro nulo integral pode ser convertida emstd::nullptr_t
. A direção oposta não é permitida. Isso permite sobrecarregar uma função para ponteiros e números inteiros e passarnullptr
para selecionar a versão do ponteiro. PassarNULL
ou0
selecionar de forma confusa aint
versão.Uma conversão de
nullptr_t
para um tipo integral precisa dereinterpret_cast
ae tem a mesma semântica que uma conversão de(void*)0
para um tipo integral (implementação de mapeamento definida). Areinterpret_cast
não pode ser convertidonullptr_t
em nenhum tipo de ponteiro. Confie na conversão implícita, se possível ou usestatic_cast
.A Norma exige que
sizeof(nullptr_t)
sejasizeof(void*)
.fonte
cond ? nullptr : 0;
. Removido da minha resposta.NULL
nem é garantido que seja0
. Pode ser0L
, nesse caso, uma chamada paravoid f(int); void f(char *);
será ambígua.nullptr
sempre favorecerá a versão do ponteiro e nunca a chamaráint
. Observe também quenullptr
é conversível embool
(o rascunho diz isso em4.12
).int
versão. Masf(0L)
é ambíguo, porquelong -> int
tambémlong -> void*
é igualmente caro. Portanto, se NULL estiver0L
no seu compilador, uma chamadaf(NULL)
será ambígua, dadas essas duas funções. Não é assim, énullptr
claro.(void*)0
em C ++. Mas pode ser definido como qualquer constante arbitrária de ponteiro nulo, que qualquer constante integral com valor 0 enullptr
preencha. Então, definitivamente não vai, mas pode . (Você se esqueceu de mim o ping btw ..)From nullptr: Um ponteiro nulo seguro e de tipo claro :
Outras referências:
template
fonte
Por que nullptr em C ++ 11? O que é isso? Por que NULL não é suficiente?
Alex Allain, especialista em C ++, diz isso perfeitamente aqui (minha ênfase foi adicionada em negrito):
Allain termina seu artigo com:
(Minhas palavras):
Por fim, não esqueça que
nullptr
é um objeto - uma classe. Ele pode ser usado em qualquer lugar queNULL
foi usado antes, mas se você precisar do tipo por algum motivo, ele pode ser extraído comdecltype(nullptr)
, ou diretamente descrito comostd::nullptr_t
, o que é simplesmente umtypedef
dosdecltype(nullptr)
.Referências:
fonte
Quando você tem uma função que pode receber ponteiros para mais de um tipo, chamá-la com
NULL
é ambígua. A maneira como isso é resolvido agora é muito hacky, aceitando um int e assumindo que éNULL
.Em
C++11
que você seria capaz de sobrecarregar emnullptr_t
modo queptr<T> p(42);
seria um erro tempo de compilação em vez de um tempo de execuçãoassert
.fonte
NULL
for definido como0L
?nullptr
não pode ser atribuído a um tipo integral, como umint
mas apenas um tipo de ponteiro; um tipo de ponteiro embutido, comoint *ptr
um ponteiro inteligente, comostd::shared_ptr<T>
Acredito que essa seja uma distinção importante, porque
NULL
ainda pode ser atribuída a um tipo integral e a um ponteiro, poisNULL
é uma macro expandida à0
qual pode servir tanto como um valor inicial para umint
quanto para um ponteiro.fonte
NULL
não é garantido que seja expandido para0
.Sim. É também um exemplo do mundo real (simplificado) que ocorreu em nosso código de produção. Ele se destacou apenas porque o gcc foi capaz de emitir um aviso ao fazer a compilação cruzada em uma plataforma com largura de registro diferente (ainda não se sabe exatamente por que apenas a compilação cruzada de x86_64 para x86, avisa
warning: converting to non-pointer type 'int' from NULL
):Considere este código (C ++ 03):
Rende esta saída:
fonte
Bem, outros idiomas têm palavras reservadas que são instâncias de tipos. Python, por exemplo:
Na verdade, é uma comparação bastante próxima, porque
None
normalmente é usada para algo que não foi inicializado, mas ao mesmo tempo comparações comoNone == 0
falsas.Por outro lado, na planície C,
NULL == 0
retornaria o IIRC verdadeiro porqueNULL
é apenas uma macro retornando 0, que é sempre um endereço inválido (AFAIK).fonte
NULL
é uma macro que se expande para zero, uma conversão de zero constante para um ponteiro produz um ponteiro nulo. Um ponteiro nulo não precisa ser zero (mas geralmente é), zero nem sempre é um endereço inválido e uma conversão de zero não constante em um ponteiro não precisa ser nula, e um ponteiro nulo em uma número inteiro não precisa ser zero. Espero ter acertado tudo isso sem esquecer nada. Uma referência: c-faq.com/null/null2.htmlÉ uma palavra-chave porque o padrão a especificará como tal. ;-) De acordo com o último rascunho público (n2914)
É útil porque não converte implicitamente em um valor integral.
fonte
Digamos que você tenha uma função (f) sobrecarregada para receber int e char *. Antes do C ++ 11, se você quisesse chamá-lo com um ponteiro nulo e utilizasse NULL (ou seja, o valor 0), chamaria aquele sobrecarregado para int:
Provavelmente não é isso que você queria. C ++ 11 resolve isso com nullptr; Agora você pode escrever o seguinte:
fonte
Deixe-me primeiro dar uma implementação não sofisticada
nullptr_t
nullptr
é um exemplo sutil do idioma Return Type Resolver para deduzir automaticamente um ponteiro nulo do tipo correto, dependendo do tipo de instância à qual está sendo atribuído.nullptr
está sendo atribuído a um ponteiro inteiro,int
é criada uma instanciação de tipo da função de conversão de modelo. E o mesmo vale para ponteiros de método também.nullptr
é um literal inteiro com valor zero, você não pode usar o endereço que realizamos ao excluir & operator.Por que precisamos
nullptr
em primeiro lugar?NULL
tem algum problema, como abaixo:Conversão implícita
2️⃣ Função chamada ambiguidade
3️⃣ Sobrecarga de construtor
String s((char*)0))
,.fonte
0 costumava ser o único valor inteiro que poderia ser usado como um inicializador sem conversão para ponteiros: não é possível inicializar ponteiros com outros valores inteiros sem uma conversão. Você pode considerar 0 como um singleton consexpr sintaticamente semelhante a um literal inteiro. Pode iniciar qualquer ponteiro ou número inteiro. Mas, surpreendentemente, você descobrirá que não possui um tipo distinto: é um
int
. Então, como 0 pode inicializar ponteiros e 1 não? Uma resposta prática foi que precisamos de um meio de definir o valor nulo do ponteiro e a conversão implícita direta deint
um ponteiro é suscetível a erros. Assim, 0 tornou-se uma verdadeira fera esquisita da era pré-histórica.nullptr
foi proposto para ser uma representação constexpr real de valor nulo para inicializar ponteiros. Ele não pode ser usado para inicializar números inteiros diretamente e eliminar as ambiguidades envolvidas na definição. Pode ser definido como uma biblioteca usando a sintaxe std, mas semântica parecia ser um componente principal ausente. agora está obsoleto em favor de , a menos que alguma biblioteca decida defini-la como .NULL
na em termos de 0.nullptr
NULL
nullptr
nullptr
fonte
Aqui está o cabeçalho do LLVM.
(muito pode ser descoberto rapidamente
grep -r /usr/include/*`
)Uma coisa que salta é a
*
sobrecarga do operador (retornar 0 é muito mais amigável do que segfaulting ...). Outra coisa é que não parece compatível com o armazenamento de um endereço em tudo . O que, comparado com a maneira como ele lança os vazios * e passa os resultados NULL para ponteiros normais como valores sentinela, obviamente reduziria o fator "nunca esqueça, pode ser uma bomba".fonte
NULL não precisa ser 0. Desde que você use sempre NULL e nunca 0, NULL pode ser qualquer valor. Considerando que você programa um microcontrolador von Neuman com memória plana, que tem seus interruptores em 0. Se NULL for 0 e algo gravar em um ponteiro NULL, o microcontrolador trava. Se NULL for digamos 1024 e em 1024 houver uma variável reservada, a gravação não causará um travamento e você poderá detectar as atribuições NULL Pointer de dentro do programa. Isso não faz sentido nos PCs, mas para sondas espaciais, equipamentos militares ou médicos, é importante não colidir.
fonte