这是其中一个代码审查评论中提到的问题。
在调用delete删除任何对象之前检查NULL是否是一个好主意吗?我知道delete操作符在内部检查NULL并且是多余的,但是提出的论点是,delete作为运算符可以被重载,如果重载版本不检查NULL,则可能会崩溃。那么现在和将来,假设delete被重载了,它是否安全和合理地假设重载的delete将会检查NULL呢?根据我的理解,合理地假设第一种情况是有重载delete来处理NULL检查,并且审查点无效。你怎么看?
这是其中一个代码审查评论中提到的问题。
在调用delete删除任何对象之前检查NULL是否是一个好主意吗?我知道delete操作符在内部检查NULL并且是多余的,但是提出的论点是,delete作为运算符可以被重载,如果重载版本不检查NULL,则可能会崩溃。那么现在和将来,假设delete被重载了,它是否安全和合理地假设重载的delete将会检查NULL呢?根据我的理解,合理地假设第一种情况是有重载delete来处理NULL检查,并且审查点无效。你怎么看?
delete (T*)0;
是有效的。这只会使你的代码变得更加复杂,没有任何好处。如果operator delete
被重载,最好在操作符实现中检查null。这可以节省代码行数和错误。cout<<address<<'\n'
)。但如果它导致了未定义的行为,那么这就是你的operator delete
实现中的一个错误。 - Yakov Galkadelete
不对其参数执行任何操作(完全不进行任何处理),因此也不需要检查null。 - C. K. Youngnew
运算符时,您可以(并且应该)定义相应的自定义delete
运算符,以便在对象构造失败时可以释放已分配的内存。放置delete
对应于放置new
(当然,它也什么都不做,只返回给定指针)。 - C. K. Youngdelete
,而是将其用作“必须检查null或不符合条件”的陈述的反例。 - C. K. Young我认为这更加需要确保如果你重载了operator delete
,那么你应该始终检查NULL
,否则你会破坏语义。
在调用delete删除任何对象之前,检查是否为NULL是一个好主意吗?
不是!
int *p = NULL;
delete p ; //no effect
标准规定 [第5.3.5/2节]
如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,并在本节的其余部分中使用转换后的操作数代替原始操作数。 无论哪种选择,如果delete的操作数的值为null指针,则该操作无效。
此外,在第 18.4.1.1/13
节中
void operator delete(void* ptr) throw();
void operator delete(void* ptr, const std::nothrow_t&) throw();
默认行为:
— 对于ptr的空值,不执行任何操作。
— ptr的任何其他值都必须是先前调用默认operator new返回的值,该值没有被介入调用operator delete(void*) (17.4.3.7)所使之失效。对于这样的非空值的ptr,回收先前调用默认operator new分配的存储空间。
编辑:
James Kanze 在这里 说:
检查是否为空指针仍然是操作符 delete(或 delete[])的责任;标准并不保证它不会得到一个空指针;标准要求如果给予一个空指针,则它必须是无操作。或者实现允许调用它。根据最新草案,“提供给解分配函数的第一个参数的值可以是空指针值;如果是这样,并且解分配函数是由标准库提供的,则调用没有效果。”我不太确定“由标准库提供”这个条件的含义是什么——如果按照字面意思来理解,因为他的函数不是标准库提供的,那么这个句子似乎不适用。但不知何故,这没有意义。
bytes.com
的帖子并要求他阅读James Kanze的答案。 - Prasoon Sauravdelete
应该像你预期的那样行事,这是它的责任。也就是说,它应该将空指针处理为无操作。delete
时,你不应该检查是否为空。你应该依赖于正确实现的重载delete
。无需检查 null。delete 操作符会检查 null,因此不需要额外的检查。
delete (T*)0;
是有效的且不执行任何操作,同样地,free(NULL);
也是有效的且不执行任何操作。如果你重载了 delete
操作符,则你的实现应该具有相同的语义。标准规定了标准 delete
的工作方式,但我认为它没有说明重载的 delete
应该如何行为。为了与标准/默认行为保持一致,它应该允许输入 (T*)0
。
从标准文档中,delete
下的 18.5.1.1.13:
默认行为:如果 ptr 为空,则不执行任何操作。 否则,回收先前调用 operator new 分配的存储空间。
因此,默认情况下无需检查。
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.
}
不需要检查。如果有人过载该方法,他有责任对NULL进行任何操作。