Em um novo emprego, tenho sido sinalizado em revisões de código para códigos como este:
PowerManager::PowerManager(IMsgSender* msgSender)
: msgSender_(msgSender) { }
void PowerManager::SignalShutdown()
{
msgSender_->sendMsg("shutdown()");
}
Disseram-me que o último método deveria ser:
void PowerManager::SignalShutdown()
{
if (msgSender_) {
msgSender_->sendMsg("shutdown()");
}
}
ou seja, I deve colocar um NULL
guarda em torno da msgSender_
variável, mesmo que seja um membro de dados privados. É difícil para mim me impedir de usar palavrões para descrever como me sinto sobre esse pedaço de 'sabedoria'. Quando peço uma explicação, recebo uma ladainha de histórias de horror sobre como algum programador júnior, durante um ano, ficou confuso sobre como uma classe deveria funcionar e excluiu acidentalmente um membro que ele não deveria ter (e a definiu NULL
posteriormente) , aparentemente), e as coisas explodiram em campo logo após o lançamento do produto, e "aprendemos da maneira mais difícil, confie em nós" que é melhor NULL
verificar tudo .
Para mim, isso parece uma programação de culto de carga , pura e simples. Alguns colegas bem-intencionados estão sinceramente tentando me ajudar a 'entender' e ver como isso me ajudará a escrever um código mais robusto, mas ... Não posso deixar de sentir que eles não entendem. .
É razoável que um padrão de codificação exija que cada ponteiro não referenciado em uma função seja verificado NULL
primeiro - mesmo membros de dados privados? (Nota: para contextualizar, fabricamos um dispositivo de eletrônicos de consumo, não um sistema de controle de tráfego aéreo ou outro produto 'falha-igual-morre-de-pessoas'.)
EDIT : No exemplo acima, o msgSender_
colaborador não é opcional. Se for o caso NULL
, indica um erro. A única razão pela qual ele é passado para o construtor é que PowerManager
pode ser testado com uma IMsgSender
subclasse simulada .
RESUMO : Houve ótimas respostas para essa pergunta, obrigado a todos. Aceitei o @aaronps principalmente devido à sua brevidade. Parece haver um consenso geral bastante amplo de que:
- A
NULL
proteção obrigatória para cada ponteiro não referenciado é um exagero, mas - Você pode contornar o debate inteiro usando uma referência (se possível) ou um
const
ponteiro, e assert
As instruções são uma alternativa mais esclarecida aosNULL
guardas para verificar se as pré-condições de uma função são atendidas.
null
e não fazer nada é apenas uma maneira de mover o erro para baixo na execução, tornando muito mais difícil rastrear de volta à fonte.