在一项新工作中,我在代码审查中被标记为这样的代码:
PowerManager::PowerManager(IMsgSender* msgSender)
: msgSender_(msgSender) { }
void PowerManager::SignalShutdown()
{
msgSender_->sendMsg("shutdown()");
}
有人告诉我最后一个方法应为:
void PowerManager::SignalShutdown()
{
if (msgSender_) {
msgSender_->sendMsg("shutdown()");
}
}
即,即使它是私有数据成员,我也必须对它进行NULL
保护msgSender_
。我很难克制自己,不能用粗话来形容我对这块“智慧”的感觉。当我要求解释时,我听到一系列恐怖故事,这些故事是关于某位初级程序员如何在某年内对类应该如何工作感到困惑的,并意外删除了一个他本不应该拥有的成员(然后将其设置为NULL
之后) (显然)),并且在产品发布后,事情就在现场爆发。我们已经“学到了硬道理,相信我们”,最好NULL
检查一下所有内容。
在我看来,这就像简单而简单的货物崇拜编程。一些好心的同事正在认真地尝试帮助我“了解它”,并了解这将如何帮助我编写更强大的代码,但是...我忍不住觉得自己是不了解它的人。
编码标准要求首先检查函数中解引用的每个指针NULL
(甚至是私有数据成员)是否合理?(注意:为提供背景信息,我们生产的是消费类电子设备,而不是空中交通管制系统或其他“故障等同人员死亡”的产品。)
编辑:在上面的示例中,msgSender_
协作者不是可选的。如果是NULL
,则表明存在错误。传递给构造函数的唯一原因是PowerManager
可以使用模拟IMsgSender
子类进行测试。
简介:对此大家有一些非常好的答案,谢谢大家。我接受@aaronps的邮件是因为它简短。似乎有相当广泛的普遍同意:
- 强制规定
NULL
看守每一个复引用指针是矫枉过正,但 - 您可以通过使用参考(如果可能)或
const
指针来避开整个辩论,并且 assert
语句是NULL
警卫人员的更开明的选择,用于验证是否满足函数的前提条件。
null
和不执行任何操作只是将错误转移到执行过程中的一种方法,这使得追溯到源代码变得更加困难。