删除NULL指针是否安全?


299

删除NULL指针是否安全?

这是一种好的编码风格吗?


21
优良作法是编写C ++程序,而不用单独调用delete。请改用RAII。也就是说,使用std::vector<T> v(100);替代T* p = new T[100];,使用智能指针像unique_ptr<T>shared_ptr<T>该照顾的缺失,而不是原始指针等
fredoverflow

8
感谢make_shared(C ++ 11)和make_unique(C ++ 14)你的程序应该包含newdelete
sp2danny

2
在某些情况下,仍然可能需要重新输入/删除,例如atomic <T *>:atomic <unique_ptr <T >>是不允许的,而atomic <shared_ptr <T >>的开销在某些情况下可能是不可接受的。
2015年

2
要使用RAII使用资源管理声明一个类,您需要调用new并删除对吗?或者您说的是有一些模板类来隐藏它。
VinGarcia '16

2
@VinGarcia关键是,大多数用户/客户端(即非库)代码永远不必编写newdelete。专为管理资源而设计的类(其中Standard组件无法胜任)当然可以完成他们需要做的事情,但是重点是它们利用它们管理的内存而不是最终用户代码来处理丑陋的事情。因此,使您自己的库/帮助程序类执行new/ delete,然后使用该类代替它们。
underscore_d

Answers:


265

delete无论如何都会执行检查,因此在您这一边进行检查会增加开销,并且看起来更难看。一个非常好的做法后,指针设置为NULL delete(有助于避免双重缺失和其它类似的内存损坏问题)。

我也很喜欢delete默认情况下是否将参数设置为NULL,例如

#define my_delete(x) {delete x; x = NULL;}

(我知道R和L值,但这不是很好吗?)


72
请注意,即使在删除时将其设置为NULL,仍然会有多个其他指针指向同一对象。
某事

13
在我的代码中,大多数情况下,指针被删除后就会超出范围。比仅将其设置为NULL更安全。
jalf

142
一个非常好的做法是删除后不要将指针设置为NULL。将指针删除后将其设置为NULL会伪装内存分配错误,这是非常不好的事情。正确的程序不会两次删除指针,并且两次删除一次指针的程序应该崩溃。
达蒙

15
@爱丽丝:这方面的标准无关紧要。该标准定义删除空指针在30年前出于某种荒谬的原因是有效的,因此它是合法的(很可能是C遗留物)。但是两次删除同一指针(即使在更改其位模式之后)仍然是严重的程序错误。不是通过标准的措辞,而是通过程序逻辑和所有权。与删除空指针一样,由于空指针不对应任何object,因此可能无法删除任何内容。程序必须确切知道对象是否有效以及谁拥有它,以及何时可以删除它。
戴蒙2014年

27
@Damon但是,尽管废除了严格的所有权规则,事实证明,无锁结构比基于锁的结构更坚固。是的,我的同事的确很爱我,因为这些结构提供了增强的执行配置文件以及它们维护的严格的线程安全性,这使人们更容易推理代码(非常适合维护)。但是,这一切或您暗示的人身攻击都与正确性,有效性或所有权的任何定义无关。您提出的建议是一个很好的经验法则,但它不是普遍适用的法律,也不包含在标准中。
爱丽丝

77

来自C ++ 0x标准草案。

$ 5.3.5 / 2-“ [...]在任一替代方案中,删除操作数的值都可以为空指针值。[...'“

当然,没有人会用NULL值“删除”一个指针,但是这样做是安全的。理想情况下,不应包含删除NULL指针的代码。但是有时在循环中删除指针(例如在容器中)时有时会很有用。由于删除NULL指针值是安全的,因此可以真正编写删除逻辑,而无需显式检查要删除的NULL操作数。

顺便说一句,C Standard $ 7.20.3.2还说NULL指针上的“ free”不起作用。

free函数使ptr指向的空间被释放,即可以用于进一步分配。如果ptr是空指针,则不执行任何操作。


2
如果它不是故意在未优化的代码中引入效率低下的问题,我真的很想得到这个答案。如公认的答案所述,空指针的删除是无操作的。因此,在删除指针之前检查指针是否为null完全是多余的。
codetaku

47

是的,这很安全。

删除空指针没有任何危害;如果将未分配的指针初始化为零然后简单地删除,则通常会减少函数尾部的测试次数。


由于前一句话引起了混乱,因此正在描述的示例(并非异常安全):

void somefunc(void)
{
    SomeType *pst = 0;
    AnotherType *pat = 0;

    
    pst = new SomeType;
    
    if (…)
    {
        pat = new AnotherType[10];
        
    }
    if (…)
    {
        code using pat sometimes
    }

    delete[] pat;
    delete pst;
}

可以使用示例代码来挑选各种各样的东西,但是(我希望)这个概念很清楚。指针变量被初始化为零,因此delete函数末尾的操作不需要测试它们在源代码中是否为非空;库代码仍然执行该检查。


为了使它有意义,我不得不读了几次。您一定要在方法的顶部或过程中而不是在尾部将它们初始化为零,确定吗?否则,您将只删除调零和删除。
洛恩侯爵

1
@EJP:一个并非完全不可信的函数的轮廓可能是:void func(void) { X *x1 = 0; Y *y1 = 0; … x1 = new[10] X; … y1 = new[10] Y; … delete[] y1; delete[] x1; }。我没有显示任何块结构或跳转,但是delete[]由于开始时进行了初始化,因此最后的操作很安全。如果某个东西在x1分配之后和分配之前跳到最后,并且y1没有初始化y1,则将存在未定义的行为-尽管代码可以在删除之前测试(of x1y1)是否为空,但无需这样做所以。
乔纳森·莱夫勒2014年

22

删除空指针无效。它不一定是好的编码风格,因为它不是必需的,但也不错。

如果您正在寻找良好的编码习惯,请考虑使用智能指针,这样就根本不需要delete


20
人们想删除NULL指针的时间是他们不确定不确定它是否包含NULL时...如果他们知道它是NULL,那么他们就不会考虑删除并因此询问;-)。
托尼·德罗伊

@Tony:我的意思是,它不会起作用,并且删除了有时包含NULL的指针的此类代码并不一定是不好的。
Brian R. Bondy 2010年

3
IMO冗余检查肯定对性能,可读性和可维护性不利。
paulm 2014年

@paulm OP当然不是在谈论那种坏,更多的是Seg Fault / UB那种坏。


3

除非您重载了delete运算符,否则它是安全的。如果重载了delete运算符并且不处理空条件,那么它根本不安全。


您能为您的答案添加任何解释吗?
MarcinNabiałek'14

-2

我所经历的,这是不是安全的(VS2010)删除[] NULL(即数组语法)。我不确定这是否符合C ++标准。

安全的删除NULL(标量语法)。


6
这是非法的,我不相信。
Konrad Rudolph

5
您应该能够删除任何空指针。因此,如果它对您不利,那么您可能会在显示它的代码中有一个错误。
Mysticial 2013年

3
§5.3.2在第二个替代方案(删除数组)中,删除操作数的值可以是空指针值,也可以是由先前数组new-expression产生的指针值。
sp2danny

1
@Opux答案中声称的VS2010行为。正如其他评论中所述,这样做是安全的delete[] NULL
康拉德·鲁道夫

1
@Opux这就是为什么我写“我不相信”而不是“那是错误的”的原因。但是我仍然不这样做,这将是对标准的相当残酷,愚蠢的违反。实际上,VC ++通常很擅长遵循该标准的限制,而从历史上讲,违反该限制的地方就很有意义。
康拉德·鲁道夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.