在我们的代码库中,我们有许多这样的结构:
auto* pObj = getObjectThatMayVeryRarelyBeNull();
if (!pObj) throw std::runtime_error("Ooops!");
// Use pObj->(...)
在99.99%的情况下,不会触发此检查。我正在考虑以下解决方案:
auto& obj = deref_or_throw(getObjectThatMayVeryRarelyBeNull());
// Use obj.(...)
deref_or_throw
声明如下:
template<class T> T& deref_or_throw(T* p) {
if (p == nullptr) { throw std::invalid_argument("Argument is null!"); }
return *p;
}
该代码更清晰,可以根据需要使用。
问题是:我是否重新发明轮子?在标准或提升中是否有一些相关的解决方案?或者你对解决方案有一些评论吗?
PS。相关问题(没有令人满意的答案):Is there a C++ equivalent of a NullPointerException
答案 0 :(得分:4)
有两种方法可以处理&#34;空指针的罕见情况&#34;问题。首先,它是建议的异常解决方案。为此,方法deref_or_throw
是一件好事,但我更倾向于抛出runtime_error
而不是invalid_argument
例外。如果您愿意,也可以考虑将其命名为NullPointerException
。
但是,如果ptr != nullptr
案例实际上是算法的前提条件,那么您应该尽量在这种非空案例中实现100%的安全性。在这种情况下,assert
是合适的。
assert
的优点:
assert
的缺点:
您还应该考虑编写方法getObjectThatMayNeverBeNullButDoingTheSameAsGetObjectThatMayVeryRarelyBeNull()
:一种方法,可以保证返回一个非空指针,该指针与对象完全等效于原始方法。但是,如果你可以加倍努力,我强烈建议不要再返回原始指针。包含C ++ 11并按值返回对象: - )
答案 1 :(得分:1)
您可以并且可能应该考虑null
个案例。例如,在您的问题域中,何时返回null
类方法是否有意义?何时用null
参数调用函数是否有意义?
从广义上讲,尽可能从代码中删除null
引用会很有用。换句话说,你可以编程为不变的&#34;这里不会为空......或者那里&#34;。这有很多好处。您不必通过在deref_or_throw
中包装方法来混淆代码。你可以从代码中获得更多的语义含义,因为在现实世界中事物null
的频率是多少?如果使用异常来指示错误而不是null
值,则代码可能更具可读性。最后,您减少了错误检查的需要,并降低了运行时错误的风险(可怕的空指针取消引用)。
如果您的系统设计时没有考虑null
个案例,我说它最好不要管它,不疯狂地用{包裹一切{1}}。也许采取敏捷方法。在编写代码时,请检查类对象提供的服务合同。这些合同多久可以合理地返回deref_or_throw
?在这些情况下null
的语义值是多少?
您可能会识别系统中可能合理预期返回null
的类。对于这些类,null
可能是有效的业务逻辑,而不是指示实现错误的边缘情况。对于可能会返回null
的类,附加检查可能值得安全。从这个意义上讲,检查null
感觉更像是业务逻辑而不是低级实现细节。但是,在整个董事会中,系统地将所有指针顺序包裹在null
中可能是一种治疗方法,也就是它自己的毒药。