In un nuovo lavoro, sono stato contrassegnato con recensioni di codice per codice come questo:
PowerManager::PowerManager(IMsgSender* msgSender)
: msgSender_(msgSender) { }
void PowerManager::SignalShutdown()
{
msgSender_->sendMsg("shutdown()");
}
Mi è stato detto che l'ultimo metodo dovrebbe essere:
void PowerManager::SignalShutdown()
{
if (msgSender_) {
msgSender_->sendMsg("shutdown()");
}
}
cioè, I deve mettere una guardia NULL
attorno alla variabile msgSender_
, anche se è un membro dati privato. È difficile per me trattenermi dall'usare le imprecazioni per descrivere ciò che provo per questo pezzo di "saggezza". Quando chiedo una spiegazione, ottengo una litania di storie dell'orrore su come alcuni programmatori junior, alcuni anni, si sono confusi su come una classe avrebbe dovuto funzionare e ha cancellato per errore un membro che non avrebbe dovuto (e impostato su NULL
dopo, apparentemente), e le cose sono esplose sul campo subito dopo la release di un prodotto, e abbiamo "imparato nel modo più duro, fidati di noi" che è meglio solo NULL
controllare tutto .
Per me, mi sento come programmazione settoriale dei carichi , semplice e semplice. Alcuni colleghi ben intenzionati stanno seriamente cercando di aiutarmi a "capirlo" e vedere come questo mi aiuterà a scrivere codice più robusto, ma ... Non posso fare a meno di sentirmi come se fossero quelli che non capiscono .
È ragionevole che uno standard di codifica richieda che ogni singolo puntatore sottoposto a dereferenziazione in una funzione sia controllato per NULL
in primo luogo, anche per i membri di dati privati? (Nota: per dare qualche contesto, realizziamo un dispositivo elettronico di consumo, non un sistema di controllo del traffico aereo o un altro prodotto "guasto-uguale-persone-muoiono".
EDIT : nell'esempio precedente, il msgSender_
collaborator non è facoltativo. Se è sempre NULL
, indica un bug. L'unica ragione per cui è passato al costruttore è quindi che PowerManager
può essere testato con una sottoclasse mock IMsgSender
.
SUMMARY : ci sono state alcune risposte davvero grandi a questa domanda, grazie a tutti. Ho accettato quello di @aaronps principalmente per la sua brevità. Sembra esserci un accordo generale abbastanza ampio che:
- Obbligare
NULL
guards per ogni singolo puntatore senza riferimenti è eccessivo, ma - Puoi eseguire il side-step dell'intero dibattito utilizzando invece un riferimento (se possibile) o un puntatore
const
e -
Le dichiarazioni
assert
sono un'alternativa più chiara aNULL
guards per verificare che le precondizioni di una funzione siano soddisfatte.