gpt4 book ai didi

c++ - 我是否应该始终检查 nullptr 的成员指针?

转载 作者:搜寻专家 更新时间:2023-10-31 00:29:45 25 4
gpt4 key购买 nike

做这样的事情不好吗? (在使用对象指针进行操作之前不检查 draw() 函数内的 nullptr)

class SomeClass
{
public:
SomeClass(Object& someValidObject)
{
object = &someValidObject;
}

void draw()
{
object->draw();
}

Object* object = nullptr;
}

或者我是否应该在调用对象中的操作之前始终检查 nullptr,即使构造函数肯定会使指针指向某物?

void draw()
{
if(object != nullptr)
object->draw?
}

最佳答案

取决于您要防范什么。

正如指出的那样in the comments已经,您无法可靠地检查悬挂指针,因此如果传递的 Object 在您的 SomeClass 之前超出范围,就会发生不好的事情。

因此,您唯一可以可靠地检查的是指针是否为 nullptr,但正如您自己注意到的那样,目前构造函数几乎不可能做到这一点。但是,只要您的 object 成员变量像现在这样是 public,理论上用户可以到达那里并将其设置为 nullptr .您可以通过使成员 private 并使用拒绝 nullptr 值的 setter(或简单地采用引用,如构造函数)来使其变得更难。在这样的设计中,object != nullptr 可以被认为是一个class invariant,这是一个在每个成员函数调用前后都为真的条件(从构造后的时间开始)直到销毁之前)。

那么我们如何打破类不变量呢?作为客户,我们可以违反函数的先决条件,从而使类进入未定义状态。对于像您的示例一样简单的类,这很难做到,因为函数实际上没有先决条件。但是,为了争论起见,我们假设您要添加这样的 setter:

// Precondition: obj must point to a valid Object.
// That object must be kept alive for the lifetime of the class,
// otherwise the behavior is undefined.
void setObject(Object* obj)
{
object = obj;
}

现在这有点微妙。代码允许我们在此处传递一个 nullptr,但文档明确禁止这样做。如果我们传递一个 nullptr 或让传递的对象在我们的 SomeClass 之前消亡,我们就违反了该类的约定。但是这个契约并没有在代码中强制执行,它只在注释中。

这里要认识到的重要一点是,有些情况无法在代码中检查。我们可以检查 nullptr,但不能检查悬挂指针。有时检查是可能的,但由于运行时成本高而不受欢迎(例如,检查一个范围是否已排序以进行二分查找)。一旦我们意识到这一点,很明显我们作为类设计者在这里有一些回旋余地。既然我们无论如何都不能使事情 100% 防弹,我们是否应该检查任何东西?当然,我们可以在任何地方检查 nullptr,但这意味着要付出运行时开销来检查基本上是编程错误的内容。

如果我不想在生产构建中支付这笔开销怎么办?如果我在开发过程中犯了错误,我可能希望我的调试器能够捕捉到它,但我不希望我的客户必须在发布后支付检查费用。

所以你真正要找的是断言:

void draw()
{
assert(object);
object->draw();
}

决定是检查断言中的某些内容(或根本不检查)还是进行适当的运行时检查(作为契约(Contract)的一部分)并不是一件容易的事情。这往往是一个哲学问题。 John Lakos 给出了出色的 talk about this at CppCon 2014如果您想深入挖掘。

关于c++ - 我是否应该始终检查 nullptr 的成员指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39715484/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com