为什么C++允许删除空指针?

8

我记得在某个地方读到过,在C++中,delete NULL是必须是一个有效的操作,但我不记得为什么它应该是这样的。请问有人能够提醒我吗?


另一种看待这个问题的方式是反过来问;你可以保证NULL永远不会指向任何东西,因此你是否希望delete NULL抛出异常呢?或者更糟糕的是,如果标准未定义并且在不同编译器之间存在不一致的行为,那该怎么办呢? - Ben Cottrell
7个回答

14

确切原因:

  • 因为C++标准委员会做出了这样的决定。

可能的推理:

  • 因为在用户代码中在调用delete之前检查每个指针是否为NULL会导致过多的代码膨胀。

11

这个规则并非必须的,因为语言在没有它的情况下也可以存在;它只是标准委员会做出的一个决定。空指针不是有效的内存地址。然而,我认为每个决定都有其原因,这些原因值得了解。

这个规则简化了操作失败情况和其他指针可能为空的情况的管理。这是一种简单、廉价的检查方式,并且它为语言增加了实用性。

例如,如果存在许多会导致动态内存分配的条件,但同时也存在其他不需要分配内存的情况,那么只需在末尾放置一个delete便可方便地处理问题。

// contrived example
void foo(int n) {
    char *p = nullptr;
    switch(n) {
        case whatever:
        case something_else:
            p = new char[n];
            break;
    }

    // some code...

    delete [] p;  // look Ma, no check!
}
如果delete nullptr是非法的,那么每次调用delete都会被包围在...。
if(ptr)

...这将很糟糕。因为这将成为一种惯例,几乎是强制性的惯例,为什么不彻底消除检查的必要性呢?每次调用delete都需要额外的5个字符(至少)吗?


1
@LuchianGrigore:在这个美好的星期五晚上,我可能至少喝了七杯葡萄酒……我写了delete n,是吧? :D - Ed S.
有没有一些平台上 0 是一个有效的内存地址? - stijn
只适用于C ++吗?我相当确定我看到过内部存储器从0开始的dsp平台,但那是在C中。或者也许它们只是不符合规定。 - stijn
3
@stijn: 我需要纠正自己;空指针必须始终是无效的。 空指针不一定是0NULL是在C语言中被定义为0的宏。该语言本身用空指针及其语义来表达。 在实践中,它们通常是相同的,但不一定如此。我必须检查标准:D - Ed S.
在Linux中,可以将0作为有效的内存地址,但出于安全原因,默认情况下已禁用。但是当运行MS-DOS程序时,Wine仍然会使用它,因为它仍然很有用。 - BatchyX
显示剩余2条评论

3
首先,NULL在托管的C++程序中永远不是有效的指针值,因此指针是否指向活动对象没有任何歧义。其次,内部内存管理逻辑必须进行自己的检查以进行簿记,因此规定指针为非空指针可能不会带来任何好处。
现在我们知道没有任何反对这个规则的理由,下面是支持这个规则的重要论点:它使编写代码更加容易。考虑这段简单的异常处理分配代码:
T * p1 = NULL;
T * p2 = NULL;
T * p3 = NULL;

try
{
    p1 = new T;
    p2 = new T;
    p3 = new T;
}
catch (...)
{
    delete p1;
    delete p2;
    delete p3;

    throw;
}

这段代码简单明了,如果我们需要在各处添加NULL检查,那么将使代码变得难以阅读并且混淆代码的逻辑。


2

因为标准委员会知道没有程序可以将NULL指向有效的对象,即NULL不能指向有效的内存,所以写delete NULL是安全的,确切地说它并没有删除任何东西。既然这样是安全的,那么在delete之前不需要检查NULL,这样就可以节省时间。

//if (ptr != NULL) NOT NEEDED
   delete ptr; //safe even if ptr == NULL

2
因为库实现者只需要写一次 if (ptr == nullptr) return;。而你作为用户,需要在整个程序中写9999999999次。因此,在delete内部执行它是更简单的解决方案。

1

如果释放函数是标准库中提供的函数,则删除空指针没有任何效果,因此在调用delete之前不必检查空指针。

还要检查删除空指针是否安全?它可能会对您有所帮助。


0

恩,我清楚地记得删除指向const的指针(现在可以)的规则随着标准化发生了变化,即它们在ARM、注释参考手册中是不同的。

但是我不确定删除0;我认为它一直被支持。

无论如何,这只涉及到方便,对于一个成本检查微不足道的操作,而且编译器可能比某些用户定义的删除包装函数更有效地完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接