È sicuro controllare un puntatore al non essere NULL
scrivendo semplicemente if(pointer)
o devo usare if(pointer != NULL)
?
NULL
in C ++ da qui in poi perché la NULL
macro dipende dall'implementazione che potrebbe darti comportamenti ambigui.
È sicuro controllare un puntatore al non essere NULL
scrivendo semplicemente if(pointer)
o devo usare if(pointer != NULL)
?
NULL
in C ++ da qui in poi perché la NULL
macro dipende dall'implementazione che potrebbe darti comportamenti ambigui.
Risposte:
Puoi; il puntatore null viene implicitamente convertito in booleano false mentre i puntatori non null vengono convertiti in true. Dallo standard C ++ 11, sezione sulle conversioni booleane:
Un valore di aritmetica, enumerazione senza ambito, puntatore o puntatore al tipo di membro può essere convertito in un valore di tipo
bool
. Viene convertito un valore zero, un valore del puntatore nullo o un valore del puntatore del membro nullfalse
; qualsiasi altro valore viene convertito intrue
. Un valore di tipostd::nullptr_t
può essere convertito in un valore di tipobool
; il valore risultante èfalse
.
Sì, potresti.
Questo fa parte della conversione standard C ++, che rientra nella clausola di conversione booleana :
§ 4.12 Conversioni booleane
Un valore di aritmetica, enumerazione senza ambito, puntatore o puntatore al tipo di membro può essere convertito in un valore di tipo bool. Un valore zero, un valore del puntatore nullo o un valore del puntatore del membro null viene convertito in false; qualsiasi altro valore viene convertito in vero. Un valore di tipo std :: nullptr_t può essere convertito in un valore di tipo bool; il valore risultante è falso.
Si, puoi. In effetti, preferisco usare if(pointer)
perché è più semplice leggere e scrivere una volta che ti ci abitui.
Si noti inoltre che è stato introdotto C ++ 11 nullptr
preferito rispetto a NULL
.
if(som_integer)
vs if(some_integer != 0)
perché anche gli interi non sono booleani, giusto? Preferisco evitare 0
o NULL
in una dichiarazione if.
if (pointer)
me stesso, ma mi if (ptr != nullptr)
sembra perfettamente legittimo. D'altra parte, se vedessi qualcuno nella mia squadra che ha scritto, if (some_integer)
lo farei cambiare if (some_integer != 0)
. Tuttavia, non pretendo che non sia una preferenza relativamente arbitraria da parte mia: semplicemente preferisco non trattare i puntatori e gli interi allo stesso modo.
if(isReady)
if(filePtr)
if(serviceNo)
? Fare intenzionalmente nomi di variabili errati non significa molto in questo caso. Ad ogni modo ho già capito il tuo punto e l'ho capito, ma posso insistere usando il mio stile di codifica, ok?
Risposte alla domanda, ma vorrei aggiungere i miei punti.
Preferirò sempre if(pointer)
anziché if(pointer != NULL)
e if(!pointer)
invece di if(pointer == NULL)
:
Meno possibilità di scrivere un codice errato, supponiamo che se ho sbagliato a scrivere l'operatore di controllo dell'uguaglianza ==
con =
if(pointer == NULL)
possa essere errato if(pointer = NULL)
Quindi lo eviterò, il migliore è giusto if(pointer)
.
(Ho anche suggerito alcune condizioni di Yoda in una risposta , ma questa è una questione diversa)
Allo stesso modo while (node != NULL && node->data == key)
, scriverò semplicemente while (node && node->data == key)
che è più ovvio per me (mostra che usare il corto circuito).
(boolean expression)? true : false
è completamente inutile. L'espressione valuta true
o to false
; quello che dici è "se è vero, dammi vero, se è falso, dammi falso". In breve: è completamente equivalente all'espressione booleana stessa. Nota che node == NULL
è un'espressione booleana. A proposito, le tue due implementazioni restituiscono esattamente il contrario l'una dell'altra. O vuoi !=
nel primo o solo uno !
nel secondo.
=
invece di ==
è rendere le variabili const
ogni volta che è possibile. Ad esempio, è possibile definire la funzione come isEmnpy(node* const head) { ... }
, quindi il compilatore rifiuta di compilarla se si scrivesse accidentalmente node = NULL
anziché node == NULL
. Ovviamente funziona solo con variabili che non è necessario modificare.
T* get() const
invece di operator T*() const
evitare conversioni implicite. Hanno comunque un operator bool() const
.
Si, puoi. La possibilità di confrontare implicitamente i valori con gli zeri è stata ereditata da C ed è presente in tutte le versioni di C ++. Puoi anche usare if (!pointer)
per controllare i puntatori per NULL.
I casi d'uso rilevanti per i puntatori null sono
Calchi dinamici. Lanciare un puntatore di classe base su un particolare di classe derivata (qualcosa che dovresti ancora tentare di evitare, ma a volte potresti ritenere necessario) ha sempre successo, ma si traduce in un puntatore nullo se la classe derivata non corrisponde. Un modo per verificarlo è
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != nullptr) { ... }
(o, preferibilmente, auto derived_ptr = ...
). Ora, questo è negativo, perché lascia il puntatore derivato (possibilmente non valido, cioè nullo) al di fuori if
dell'ambito del blocco di protezione di sicurezza . Questo non è necessario, come C ++ consente di introdurre variabili booleane-Convertable all'interno di un if
Circostanza :
if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
che non è solo più breve e sicuro per l'ambito, è anche molto più chiaro nella sua intenzione: quando si verifica la presenza di null in una condizione if separata, il lettore si chiede "ok, quindi derived_ptr
non deve essere null qui ... beh, perché dovrebbe essere nullo? " Mentre la versione di una sola riga dice molto chiaramente: "Se si può tranquillamente lanciare base_ptr
a Derived*
, quindi usarlo per ...".
Lo stesso vale anche per qualsiasi altra operazione di errore possibile che restituisce un puntatore, anche se IMO dovresti generalmente evitarlo: è meglio usare qualcosa come boost::optional
il "contenitore" per risultati di possibili operazioni fallite, piuttosto che puntatori.
Quindi, se il caso d'uso principale per i puntatori null dovesse sempre essere scritto in una variante dello stile di cast implicito, direi che è buono per motivi di coerenza usare sempre questo stile, vale a dire difenderei per if(ptr)
over if(ptr!=nullptr)
.
Temo di dover finire con un annuncio: la if(auto bla = ...)
sintassi è in realtà solo un'approssimazione leggermente ingombrante alla vera soluzione a tali problemi: il pattern matching . Perché prima dovresti forzare qualche azione (come lanciare un puntatore) e poi considerare che potrebbe esserci un fallimento ... Voglio dire, è ridicolo, non è vero? È come se avessi del cibo e vuoi fare una zuppa. Lo passi al tuo assistente con il compito di estrarre il succo, se capita di essere una verdura morbida. Prima non lo guardi. Quando hai una patata, la dai ancora al tuo assistente, ma te la schiaffeggiano in faccia con una nota di fallimento. Ah, programmazione imperativa!
Molto meglio: considera subito tutti i casi che potresti incontrare. Quindi agire di conseguenza. 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 ha anche strumenti speciali per quando c'è davvero una seria possibilità di fallimento (così come per un sacco di altre cose): le monadi. Ma questo non è il posto giusto per spiegarli.
⟨/ Advert⟩
if(ptr)
piuttosto che if(ptr != nullptr)
, a cui c'è ancora molto da dire.
sì, naturalmente! in effetti, scrivere if (pointer) è un modo più conveniente di scrivere piuttosto che if (pointer! = NULL) perché: 1. è facile eseguire il debug 2. facile da capire 3. se per caso, viene definito il valore di NULL, quindi anche il codice non andrà in crash
Sì. In effetti dovresti. Se ti stai chiedendo se crea un errore di segmentazione , non lo fa.
Come altri hanno già risposto bene, entrambi sono intercambiabili.
Tuttavia, vale la pena ricordare che potrebbe esserci un caso in cui potresti voler usare la dichiarazione esplicita, ad es pointer != NULL
.
Vedi anche https://stackoverflow.com/a/60891279/2463963
Sì, puoi sempre farlo mentre la condizione 'IF' viene valutata solo quando la condizione al suo interno diventa vera. C non ha un tipo di ritorno booleano e quindi restituisce un valore diverso da zero quando la condizione è vera mentre restituisce 0 ogni volta che la condizione in 'IF' risulta essere falsa. Il valore diverso da zero restituito per impostazione predefinita è 1. Pertanto, entrambi i modi di scrivere il codice sono corretti mentre preferirò sempre il secondo.
Penso come regola empirica, se la tua espressione if può essere riscritta come
const bool local_predicate = *if-expression*;
if (local_predicate) ...
tale da non causare AVVERTENZE, quindi QUELLO dovrebbe essere lo stile preferito per l' espressione if . (So di ricevere avvisi quando assegno un vecchio C BOOL
( #define BOOL int
) a un C ++ bool
, per non parlare dei puntatori.)
"È sicuro..?" è una domanda sullo standard di lingua e sul codice generato.
"È una buona pratica?" è una domanda sul modo in cui l'affermazione è compresa da qualsiasi lettore umano arbitrario dell'affermazione. Se stai ponendo questa domanda, suggerisce che la versione "sicura" è meno chiara per i futuri lettori e scrittori.
0
onullptr
. (NULL
è un C'ism e richiede l'inclusione di un file di intestazione.)