Este exemplo parece ser mais sobre a vida útil do objeto do que se um parâmetro de entrada é nulo ou não †. Como você mencionou que PowerManager
deve sempre ter um IMsgSender
válido, passar o argumento por ponteiro (permitindo assim a possibilidade de um ponteiro nulo) me parece uma falha de design ††.
Em situações como esta, prefiro alterar a interface para que os requisitos do autor da chamada sejam aplicados pela linguagem:
PowerManager::PowerManager(const IMsgSender& msgSender)
: msgSender_(msgSender) {}
void PowerManager::SignalShutdown() {
msgSender_->sendMsg("shutdown()");
}
Reescrevê-lo desta maneira diz que PowerManager
precisa manter uma referência a IMsgSender
para toda a sua vida útil. Isso, por sua vez, também estabelece um requisito implícito de que IMsgSender
deve viver mais do que PowerManager
e nega a necessidade de qualquer verificação de ponteiro nulo ou asserções dentro de PowerManager
.
Você também pode escrever a mesma coisa usando um ponteiro inteligente (via boost ou c ++ 11), para forçar explicitamente IMsgSender
a viver mais do que PowerManager
:
PowerManager::PowerManager(std::shared_ptr<IMsgSender> msgSender)
: msgSender_(msgSender) {}
void PowerManager::SignalShutdown() {
// Here, we own a smart pointer to IMsgSender, so even if the caller
// destroys the original pointer, we still have a valid copy
msgSender_->sendMsg("shutdown()");
}
Esse método é preferido se for possível que a vida útil de IMsgSender
não possa ser maior do que PowerManager
(ou seja, x = new IMsgSender(); p = new PowerManager(*x);
).
† Com relação aos ponteiros: a verificação nula excessiva torna o código mais difícil de ler e não melhora a estabilidade (melhora a aparência da estabilidade, que é muito pior).
Em algum lugar, alguém tem um endereço de memória para armazenar o IMsgSender
. É responsabilidade dessa função certificar-se de que a alocação foi bem-sucedida (verificar valores de retorno de biblioteca ou manipular corretamente std::bad_alloc
exceções), para não passar por ponteiros inválidos.
Como o PowerManager
não possui o IMsgSender
(é apenas emprestado por um tempo), ele não é responsável por alocar ou destruir essa memória. Esta é outra razão pela qual eu prefiro a referência.
†† Como você é novo nesse trabalho, espero que esteja invadindo o código existente. Então, por falha de design, quero dizer que a falha está no código com o qual você está trabalhando. Assim, as pessoas que estão sinalizando seu código porque ele não está verificando os ponteiros nulos estão realmente sinalizando para escrever código que requer ponteiros:)