繁体   English   中英

C ++中的安全指针解引用

[英]Safe pointer dereferencing in C++

在我们的代码库中,我们有许多类似以下的构造:

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。 相关问题(答案不令人满意): 是否有C ++等效于NullPointerException

有两种方法可以处理“空指针的罕见情况”问题。 首先,它是建议的异常解决方案。 为此,方法deref_or_throw是一件好事,尽管我宁愿抛出runtime_error ,而不是invalid_argument异常。 如果您愿意,也可以考虑将其命名为NullPointerException

但是,如果ptr != nullptr情况实际上是该算法的前提条件,则应尽最大努力使该非null情况达到100%的安全性。 在这种情况下, assert是适当的事情。

assert优点:

  • 在发布模式下运行时无成本
  • 使开发人员很清楚,他对这种情况永远不会发生负责。

assert缺点:

  • 释放模式下潜在的不确定行为

您还应该考虑编写一种方法getObjectThatMayNeverBeNullButDoingTheSameAsGetObjectThatMayVeryRarelyBeNull() :该方法保证可以返回指向对象的非null指针,否则该指针与原始方法完全等效。 但是,如果可以加倍努力,我强烈建议无论如何不要返回原始指针。 拥抱C ++ 11并按值返回对象:-)

您可以并且可能应该在设计时考虑到null例。 例如,在您的问题域中,类方法何时返回null才有意义? 什么时候使用null参数调用函数有意义?

广义上讲,只要有可能,从代码中删除null引用都是有益的。 换句话说,您可以对不变量进行编程,使其“此处或此处都不为空”。 这有很多好处。 您无需通过将方法包装在deref_or_throw来混淆代码。 您可能会从代码中获得更多的语义含义,因为在现实世界中事物多长时间为null 如果您使用异常来表示错误而不是null值,则代码可能更具可读性。 最后,您减少了错误检查的需要,并降低了运行时错误(可怕的空指针取消引用)的风险。

如果您的系统在设计时没有考虑到null情况,那么我想说最好deref_or_throw不要deref_or_throw疯狂地包装所有deref_or_throw 也许采取敏捷方法。 在编写代码时,请检查您的类对象作为服务提供的合同。 可以合理预期这些合同多久返回一次null 在这些情况下null的语义值是什么?

您可能会确定系统中可能合理预期返回null 对于这些类, null可能是有效的业务逻辑,而不是指示实现错误的边缘情况。 对于可能期望返回null ,额外的检查可能是值得的。 从这个意义上讲,检查null更像是业务逻辑,而不是底层实现细节。 但是,将所有指针deref_or_throw系统地包装在deref_or_throw可能是一种解决方法,这本身就是毒药。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM