26

这是代码审查评论之一。

在为任何对象调用 delete 之前检查 NULL 是个好主意吗?

我确实理解 delete 运算符在内部检查 NULL 并且是多余的,但提出的参数是 delete,因为运算符可以重载,如果重载版本不检查 NULL,它可能会崩溃。那么假设删除是否以及何时重载是否会检查NULL是否安全合理?在我的理解中,假设第一种情况是重载的删除应该处理 NULL 检查,并且审查点不成立是合理的。你怎么看?

4

11 回答 11

35

不,不要检查空值。标准说这delete (T*)0;是有效的。它只会使您的代码复杂化而没有任何好处。如果operator delete重载,最好在运算符的实现中检查 null。只是节省代码行和错误。

编辑:这个答案被接受和赞成,但是,在我看来,它的信息量不是很大。这里的所有答案都缺少一个,为了良心,让我在这里添加最后一个。

该标准实际上在 [basic.stc.dynamic] 中说,至少从 C++03 开始​​:

C++ 程序中定义的任何分配和/或解除分配函数,包括库中的默认版本,应符合 3.7.4.1 和 3.7.4.2 中指定的语义。

引用的部分以及其他答案中列出的标准中的其他一些地方说传递空指针的语义是无操作的。

于 2010-09-29T11:45:31.513 回答
19

我会说这更多的原因是确保如果你重载operator delete,那么你应该总是让它检查NULL,否则你会破坏语义。

于 2010-09-29T11:46:13.570 回答
7

在为任何对象调用 delete 之前检查 NULL 是个好主意吗?

不!

int *p = NULL;
delete p ; //no effect

标准说 [第 5.3.5/2 节]

如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,并在本节的其余部分使用转换后的操作数代替原始操作数。在任一替代方案中,如果 delete 的操作数的值是空指针,则该操作无效

此外在部分18.4.1.1/13

void operator delete(void* ptr) throw();

void operator delete(void* ptr, const std::nothrow_t&) throw();

默认行为:

对于 ptr 的空值,什么也不做

— ptr 的任何其他值应是先前通过调用默认操作符 new 返回的值,该值不会因对操作符 delete(void*) (17.4.3.7) 的介入调用而无效。对于 ptr 的此类非空值,回收先前调用默认运算符 new 分配的存储空间。

编辑

詹姆斯坎泽在这里

检查仍然是操作员删除(或删除[])的责任;该标准不保证不会给它一个空指针;如果给定一个空指针,该标准要求它是一个空操作。或者允许实现调用它。根据最新草案,“提供给释放函数的第一个参数的值可能是空指针值;如果是这样,并且释放函数是标准库中提供的函数,则调用无效。” 我不太确定“是标准库中提供的”的含义是什么——从字面上看,因为他的功能不是标准库提供的,所以这句话似乎不适用. 但不知何故,这没有任何意义。

于 2010-09-29T11:46:38.983 回答
6

我想说的是,重载的人有责任delete表现得像你期望delete的那样。也就是说,它应该将NULL 指针作为无操作处理。

因此,在调用重载删除时,您不应该检查NULL。您应该依靠重载的删除来正确实施。

于 2010-09-29T12:48:28.320 回答
3

无需检查空值。删除操作员会检查 null,因此不需要额外检查。

于 2010-09-29T11:48:25.487 回答
3

delete (T*)0;是有效的,什么也不做,同样free(NULL);也是有效的,什么也不做。如果您重载delete运算符,您的实现应该具有相同的语义。标准说明了标准delete将如何工作,但我不认为它说明了重载delete应该如何表现。为了与标准/默认行为保持一致,它应该允许(T*)0作为输入。

于 2010-09-29T11:53:16.160 回答
3

来自标准文档,18.5.1.1.13delete

默认行为:如果 ptr 为空,则不执行任何操作。否则,回收先前调用 operator new 分配的存储空间。

所以,你不必默认检查..

于 2010-09-29T11:54:30.587 回答
2

删除前无需检查 NULL。如果有人超载delete了一些不以标准方式运行的东西,那么这就是真正的问题。任何人都不应轻视重载任务,delete并且应始终支持预期的行为,例如检查 NULL 和不采取任何行动。

但是,对于它的价值,您应该始终记住将零分配给您刚刚删除的任何指针,除非您也将要删除该指针:

void MyObj::reset()
{
    delete impl_;
    impl_ = 0;    // Needed here - impl_ may be reused / referenced.
}

MyObj::~MyObj()
{
    delete impl_; // No need to assign here as impl_ is going out of scope.
}
于 2010-09-29T12:46:41.600 回答
2

是不是不需要检查。如果有人超载了方法,那么他对NULL的任何事情都是他的责任。

于 2010-09-29T13:31:56.540 回答
1

我会说这些问题包含不完整的信息。我的商店在我们的编码标准中仍然在删除之前检查 NULL,因为我们仍然有一个必须支持的编译器/平台配置,如果它被传递为 NULL,则使用默认删除运算符进入未定义的行为。如果原贴有类似的情况那么有一点要检查NULL,否则,改变编码标准!

于 2010-09-29T13:50:49.123 回答
0

有点 C++ 迂腐:NULL 不是内置概念。是的,我们都知道它的含义,但是在 C++0X 之前的 C++ 中,空指针概念就是值 0。NULL 通常是扩展为 0 的特定于平台的宏。

使用 C++0X,我们得到的 nullptr 比纯零更清晰,并且不能转换为除 bool 之外的任何整数类型,并且是比 NULL 更好的概念(或者可能是 NULL 背后概念的更好实现)。

于 2010-09-29T13:29:13.707 回答