不要仅仅检查空指针并在找到空指针时什么都不做。
如果指针允许为空,那么您必须考虑当其实际为空时您的代码会发生什么。通常,什么都不做是错误的答案。通过细心,可以定义像这样工作的API,但这需要远不止于在各个地方散布一些NULL检查。
因此,如果指针允许为空,则必须检查空指针,并执行任何适当的操作。
如果指针不允许为空,则编写在其为空时调用未定义行为的代码是完全合理的。这与编写字符串处理例程、如果输入未以NUL结尾则调用未定义行为的例程、编写使用缓冲区且调用方传递了错误长度值的例程或者编写一个接受file *
参数的函数,并在用户传递文件描述符reinterpret_cast到file *
中调用未定义行为没有任何区别。在C和C++中,您只需要能够依赖调用方告诉您什么就好,垃圾进去,垃圾出来。
但是,您可能希望编写帮助调用方(毕竟他们很可能是您自己)的代码,当传递的最可能是垃圾时。断言和异常对此很有帮助。
从Franci在问题评论中提出的类比中可以得出:大多数人在穿过人行道或在沙发上坐下之前不寻找汽车。他们仍然可能被汽车撞击。这种情况经常发生。但通常认为,在这些情况下花费任何精力检查汽车或者在罐头汤的说明书上写“首先,请检查厨房中是否有汽车。然后加热汤”是偏执的。
您的代码也是如此。将无效值传递给函数比意外驾驶汽车进入某人的厨房要容易得多。但如果司机这样做并且撞到了某人,那么这仍然是司机的过错,而不是厨师未行使谨慎责任。您不一定希望厨师(或被调用方)用应该是多余的检查来混淆他们的食谱(代码)。
除了使用单元测试和调试器等方式,还有其他方法可以找到问题。无论如何,在不必要的地方(道路)创造一个无车环境要比在任意地方随意驾驶汽车并希望每个人都能随时应对更为安全。因此,如果你在不允许的情况下检查 null 值,你不应该让这给人们留下它是被允许的想法。
[编辑 - 我刚刚遇到一个检查 null 值无法找到无效指针的 bug 示例。我将使用一个 map 来保存一些对象,并使用指针来表示一个图,这很好,因为 map 从不重新定位其内容。但我尚未为这些对象定义排序(这可能有点棘手)。所以,为了推动事情并证明一些其他代码的工作,我使用了一个 vector 和一个线性搜索而不是一个 map。没错,我不是指 vector,我是说 deque。所以,第一次 vector 调整大小后,我没有传递空指针到函数中,但我传递了指向已释放内存的指针。
我犯的愚蠢错误几乎与我无效地传递 null 指针的愚蠢错误相同频率。因此,无论我是否添加了检查 null,我仍然需要能够诊断程序因我无法检查的原因而崩溃的问题。由于这也将诊断空指针访问,除非我正在编写代码以通常检查函数进入前提条件,否则我通常不会检查 null。