É seguro verificar se um ponteiro não está NULL
escrevendo de forma simples if(pointer)
ou preciso usar if(pointer != NULL)
?
NULL
C ++ a partir daqui porque NULL
é uma macro dependente de implementação que pode fornecer comportamentos ambíguos.
É seguro verificar se um ponteiro não está NULL
escrevendo de forma simples if(pointer)
ou preciso usar if(pointer != NULL)
?
NULL
C ++ a partir daqui porque NULL
é uma macro dependente de implementação que pode fornecer comportamentos ambíguos.
Respostas:
Você pode; o ponteiro nulo é implicitamente convertido em booleano false, enquanto ponteiros não nulos são convertidos em true. No padrão C ++ 11, seção Conversões Booleanas:
Um pré-valor de aritmética, enumeração sem escopo, ponteiro ou ponteiro para o tipo de membro pode ser convertido em um pré-valor do tipo
bool
. Um valor zero, valor de ponteiro nulo ou valor de ponteiro de membro nulo é convertido emfalse
; qualquer outro valor é convertido emtrue
. Um pré-valor do tipostd::nullptr_t
pode ser convertido em um pré-valor do tipobool
; o valor resultante éfalse
.
Sim você pode.
Isso faz parte da conversão padrão do C ++, que se enquadra na cláusula de conversão booleana :
§ 4.12 Conversões booleanas
Um pré-valor de aritmética, enumeração sem escopo, ponteiro ou ponteiro para o tipo de membro pode ser convertido em um pré-valor do tipo bool. Um valor zero, um valor de ponteiro nulo ou um valor de ponteiro de membro nulo é convertido em falso; qualquer outro valor é convertido em true. Um pré-valor do tipo std :: nullptr_t pode ser convertido em um pré-valor do tipo bool; o valor resultante é falso.
Sim você pode. Na verdade, eu prefiro usar if(pointer)
porque é mais fácil ler e escrever quando você se acostumar.
Observe também que o C ++ 11 introduziu o nullptr
que é preferível NULL
.
if(som_integer)
vs if(some_integer != 0)
porque números inteiros também não são booleanos, certo? Eu prefiro evitar 0
ou NULL
em uma declaração if.
if (pointer)
me preferir , mas me if (ptr != nullptr)
parece perfeitamente legítimo. Por outro lado, se eu visse alguém da minha equipe que escrevesse, if (some_integer)
eu os faria mudar para if (some_integer != 0)
. No entanto, não vou fingir que não é uma preferência relativamente arbitrária da minha parte - simplesmente prefiro não tratar ponteiros e números inteiros da mesma forma.
if(isReady)
if(filePtr)
if(serviceNo)
? Criar nomes de variáveis incorretos de propósito não significa muito neste caso. Enfim, eu já entendi seu ponto de vista e entendi, mas posso insistir em usar meu próprio estilo de codificação, ok?
A pergunta foi respondida, mas eu gostaria de acrescentar meus pontos.
Eu vou sempre preferir if(pointer)
, em vez de if(pointer != NULL)
e if(!pointer)
em vez de if(pointer == NULL)
:
Menos chances de escrever um código de buggy, que se eu grafada operador cheque igualdade ==
com =
if(pointer == NULL)
pode ser grafada if(pointer = NULL)
Então eu vou evitá-lo, o melhor é apenas if(pointer)
.
(Eu também sugeri alguma condição Yoda em uma resposta , mas isso é uma questão diferente)
Da mesma forma while (node != NULL && node->data == key)
, escreverei o while (node && node->data == key)
que é mais óbvio para mim (mostra que usando curto-circuito).
(boolean expression)? true : false
é completamente inútil. A expressão avalia para true
ou para false
; o que você diz é "se é verdade, me dê verdadeira, se for falsa, me dê falsa". Resumindo: é completamente equivalente à própria expressão booleana. Observe que node == NULL
é uma expressão booleana. BTW, suas duas implementações retornam exatamente o oposto uma da outra. Ou você quer !=
no primeiro, ou apenas um !
no segundo.
=
vez de, ==
é fazer suas variáveis const
sempre que possível. Por exemplo, você pode definir sua função como isEmnpy(node* const head) { ... }
e, em seguida, o compilador se recusaria a compilá-la se você escrevesse acidentalmente em node = NULL
vez de node == NULL
. Claro que isso funciona apenas para variáveis que você realmente não precisa alterar.
T* get() const
vez de operator T*() const
evitar conversões implícitas. No entanto, eles têm um operator bool() const
.
Sim você pode. A capacidade de comparar valores com zeros implicitamente foi herdada de C e existe em todas as versões do C ++. Você também pode usar if (!pointer)
para verificar os ponteiros quanto a NULL.
Os casos de uso relevantes para ponteiros nulos são
Moldes dinâmicos. A conversão de um ponteiro de classe base para um de classe derivada específico (algo que você deve tentar novamente evitar, mas às vezes pode achar necessário) sempre é bem-sucedida, mas resulta em um ponteiro nulo se a classe derivada não corresponder. Uma maneira de verificar isso é
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != nullptr) { ... }
(ou, de preferência, auto derived_ptr = ...
). Agora, isso é ruim, porque deixa o ponteiro derivado (possivelmente inválido, ou seja, nulo) fora if
do escopo do bloco de proteção . Isso não é necessário, pois o C ++ permite introduzir variáveis conversíveis em booleano dentro de uma if
condição- :
if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
que não é apenas mais curto e seguro para o escopo, também é muito mais claro em sua intenção: quando você verifica nulo em uma condição if separada, o leitor se pergunta "ok, então derived_ptr
não deve ser nulo aqui ... bem, por que ser nulo? " Considerando que a versão de uma linha diz muito claramente "se você pode transmitir base_ptr
com segurança Derived*
, então use-o para ...".
O mesmo funciona da mesma forma para qualquer outra operação de falha possível que retorna um ponteiro, embora o IMO geralmente evite isso: é melhor usar algo como boost::optional
o "contêiner" para resultados de possíveis operações com falha, em vez de ponteiros.
Assim, se o caso de uso principal para ponteiros nulos deve sempre ser escrito em uma variação do-cast-style implícita, eu diria que é bom por razões de coerência para sempre usar este estilo, ou seja, eu defendo para if(ptr)
cima if(ptr!=nullptr)
.
Receio ter que terminar com um anúncio: a if(auto bla = ...)
sintaxe é, na verdade, apenas uma aproximação um pouco complicada da solução real para esses problemas: correspondência de padrões . Por que você primeiro força alguma ação (como lançar um ponteiro) e depois considera que pode haver uma falha ... Quero dizer, é ridículo, não é? É como, você tem alguns alimentos e quer fazer sopa. Você o entrega ao assistente com a tarefa de extrair o suco, se for um vegetal macio. Você não olha primeiro para isso. Quando você tem uma batata, ainda a entrega ao seu assistente, mas ele a devolve ao seu rosto com uma nota de falha. Ah, programação imperativa!
Muito melhor: considere imediatamente todos os casos que você pode encontrar. Então aja de acordo. Haskell:
makeSoupOf :: Foodstuff -> Liquid
makeSoupOf p@(Potato{..}) = mash (boil p) <> water
makeSoupOf vegetable
| isSoft vegetable = squeeze vegetable <> salt
makeSoupOf stuff = boil (throwIn (water<>salt) stuff)
Haskell também tem ferramentas especiais para quando há realmente uma possibilidade séria de falha (assim como para várias outras coisas): mônadas. Mas este não é o lugar para explicar isso.
⟨/advertir⟩
if(ptr)
e não if(ptr != nullptr)
, as quais há muito mais a dizer.
sim, claro! de fato, escrever se (ponteiro) é uma maneira mais conveniente de escrever do que se (ponteiro! = NULL) porque: 1. é fácil depurar 2. fácil entender 3. se, acidentalmente, o valor de NULL for definido, então também o código não trava
Sim. Na verdade você deveria. Se você está se perguntando se isso cria uma falha de segmentação , isso não ocorre.
Como outros já responderam bem, ambos são intercambiáveis.
No entanto, vale ressaltar que pode haver um caso em que você queira usar a declaração explícita, ie pointer != NULL
.
Consulte também https://stackoverflow.com/a/60891279/2463963
Sim, você sempre pode fazer isso como a condição 'SE' avalia apenas quando a condição interna se torna verdadeira. C não possui um tipo de retorno booleano e, portanto, retorna um valor diferente de zero quando a condição é verdadeira, enquanto retorna 0 sempre que a condição em 'IF' for falsa. O valor diferente de zero retornado por padrão é 1. Portanto, as duas maneiras de escrever o código estão corretas, enquanto eu sempre preferirei o segundo.
Eu acho que, como regra geral, se sua expressão if puder ser reescrita como
const bool local_predicate = *if-expression*;
if (local_predicate) ...
de forma que não cause AVISOS, esse deve ser o estilo preferido para a expressão if . (Eu sei que recebo avisos quando atribuo um C BOOL
( #define BOOL int
) antigo a um C ++ bool
, sem falar em indicadores.)
"É seguro..?" é uma pergunta sobre o padrão de idioma e o código gerado.
"É uma boa prática?" é uma pergunta sobre quão bem a declaração é entendida por qualquer leitor humano arbitrário da declaração. Se você está fazendo essa pergunta, sugere que a versão "segura" é menos clara para futuros leitores e escritores.
0
ounullptr
. (NULL
É um C'ism, e requer incluindo um arquivo de cabeçalho.)