删除NULL指针是否安全?

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

评论

优良作法是编写C ++程序,而无需单个调用delete。请改用RAII。也就是说,使用std :: vector v(100);代替T * p = new T [100] ;,使用诸如delete_ptr 和shared_ptr 这样的智能指针来处理删除,而不是原始指针等。

多亏了make_shared(c ++ 11)和make_unique(c ++ 14),您的程序应该包含零个new和delete

在某些情况下,仍然可能需要重新输入/删除,例如atomic :不允许atomic >,而atomic >的开销在某些情况下可能是不可接受的。 br />
要使用RAII使用资源管理声明一个类,您需要调用new并删除对吗?或者您说的是有一些模板类来隐藏它。
@VinGarcia关键是大多数用户/客户端(即非库)代码永远不必编写新的或删除的代码。设计用于管理资源的类当然可以执行其标准组件无法完成的工作,但是重点是它们使用其管理的内存而不是最终用户代码来处理难看的事情。因此,创建您自己的库/帮助程序类以进行新建/删除,并使用该类代替它们。

#1 楼

delete仍会执行检查,因此在您这一边进行检查会增加开销,并且看起来更难看。很好的做法是在delete之后将指针设置为NULL(有助于避免重复删除和其他类似的内存损坏问题)。

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


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

评论


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

– sth
10 Nov 16'2:47

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

–杰夫
10 Nov 16'4:03

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

–达蒙
13年8月30日在18:48

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

–达蒙
2014年3月17日15:01

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

–爱丽丝
2014年3月18日在15:36

#2 楼

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


$ 5.3.5 / 2-“ [...]在任一
替代方案中,操作数的值
的delete可能是空指针
值。这是安全的。理想情况下,不应包含删除NULL指针的代码。但是有时在循环中删除指针时(例如在容器中)有时很有用。由于删除NULL指针值是安全的,因此可以真正编写删除逻辑而无需显式检查要删除的NULL操作数。 NULL指针不起作用。


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


评论


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

– codetaku
16 Mar 24 '16在11:11

#3 楼

是的,这是安全的。

删除空指针没有任何危害;如果未分配的指针初始化为零然后简单地删除,则通常会减少函数尾部的测试次数。并非异常安全-所描述的内容:

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;
}


示例代码可以选择各种各样的尼特,但概念是(I希望)清楚。指针变量被初始化为零,因此函数末尾的delete操作不需要测试它们在源代码中是否为非空;库代码仍会执行该检查。

评论


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

–user207421
2014年9月8日在22:58



@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的过程跳到最后,那么就存在未定义的行为-尽管代码可以在删除之前测试(x1和y1的)空性,但是不需要这样做。

–乔纳森·莱弗勒(Jonathan Leffler)
2014年9月8日23:26

#4 楼

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

评论


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

–托尼·德罗伊(Tony Delroy)
10 Nov 16'4:44



@Tony:我的意思只是说它不会起作用,并且删除了有时包含NULL的指针的此类代码的存在不一定是不好的。

–布赖恩·邦迪(Brian R. Bondy)
10 Nov 16 '13:02

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

– paulm
2014年2月25日下午0:56

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

–冬天
17年6月26日在20:08

#5 楼

为了补充ruslik的答案,在C ++ 14中,您可以使用以下结构:

delete std::exchange(heapObject, nullptr);


#6 楼

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

评论


您能为您的答案添加任何解释吗?

– MarcinNabiałek
2014年11月16日上午11:19

#7 楼

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

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

评论


这是非法的,我不相信。

–康拉德·鲁道夫(Konrad Rudolph)
13年8月30日在16:56

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

–神秘主义者
13年8月30日在17:00

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

–sp2danny
2014年8月16日下午5:12

@Opux答案中声称的VS2010行为。如其他注释中所述,delete [] NULL是安全的。

–康拉德·鲁道夫(Konrad Rudolph)
17 Mar 14 '21在21:52

@Opux这就是为什么我写“我不相信”而不是“那是错误的”的原因。但是我仍然不这样做,这将是对标准的相当残酷,愚蠢的违反。实际上,VC ++通常很擅长遵循该标准的限制,并且从历史上讲,违反该限制的地方都是有意义的。

–康拉德·鲁道夫(Konrad Rudolph)
17年3月15日在17:03