C++ 为什么是;操作员删除";当我调用时调用";删除“;在空指针上?
在阅读对的答案时,我注意到答案(例如)意味着即使在空指针上执行C++ 为什么是;操作员删除";当我调用时调用";删除“;在空指针上?,c++,pointers,memory-management,C++,Pointers,Memory Management,在阅读对的答案时,我注意到答案(例如)意味着即使在空指针上执行delete语句,也可以调用operator delete 所以我写了一个小片段: class Test { public: void* operator new( size_t ) { /*doesn't matter*/ return 0; } void operator delete( void* ptr ) { ptr; //to suppress warning and have a line
delete
语句,也可以调用operator delete
所以我写了一个小片段:
class Test {
public:
void* operator new( size_t ) { /*doesn't matter*/ return 0; }
void operator delete( void* ptr ) {
ptr; //to suppress warning and have a line to put breakpoint on
}
};
int main()
{
Test* ptr = 0;
delete ptr;
}
而且,令我惊讶的是,Test::operator delete()
是用持有空指针的ptr
调用的
据我所知,operator new
分配内存,operator delete
将内存返回给分配器。如果我对空指针调用delete
语句,这意味着指针后面没有对象,也没有内存返回分配器
delete
语句包括调用析构函数。当我传递空指针时,析构函数肯定不会被调用——C++会处理这个问题。那么,在这种情况下,为什么要调用运算符delete
?运算符delete与任何其他运算符一样,为什么不调用它?它无法在被调用之前检查其参数
这就像询问为什么在添加0时调用
运算符+
。即将推出的C++0x标准(第5.3.5节[expr.delete]
)中的语言如下所示:
如果
delete表达式不是null
指针值,删除表达式
将调用释放函数
(3.7.4.2). 否则就是
未指定是否取消分配
函数将被调用。[注:附件]
取消分配函数被调用
不管析构函数
对于对象或对象的某个元素
数组引发异常。-结束说明]
因此,这是一种未指定的行为,当删除空指针时,一些编译器可能会调用运算符delete
,而其他编译器可能不会
编辑:标准使用的术语释放函数似乎引起了一些混乱。它附带了一个参考资料。3.7.4.2[basic.stc.dynamic.deallocation]
中的一些关键语言可能有助于澄清:
如果类T
具有名为operator delete
如果只有一个参数,则该函数是一个常用的(非放置)释放函数
该标准还非常明确,用户定义的运算符delete
需要接受一个为空指针值的参数:
价值
提供给释放函数的第一个参数可以是空指针值;如果是,如果取消分配
函数是标准库中提供的函数,调用无效
但是由于未指定的行为5.3.5,当指针为null时,您不应该依赖于调用
运算符delete
。delete语句不仅仅调用运算符delete
,它首先调用析构函数,在调用析构函数之前必须进行null检查(因此,在调用操作员之前,请删除).运算符delete
与其他运算符重载不同。好的,但编译器无法确保在给定空指针时,用户定义的运算符delete是no op。例如,它可以记录一些指示您试图删除空指针的内容。请同意Ben Voigt:键入delete p;
,t编译器首先调用对象的析构函数,然后调用释放函数operator delete
。系统必须能够诊断指针为0,以避免调用析构函数(它不会调用析构函数)因此,技术上它也可以避免调用DealLoopter。实际上,C++标准明确允许编译器避免调用空代码指针值的< C++ >运算符删除>代码。HMM,这个片段是在讨论解除分配函数,而不是操作符。C++ 03在这个问题上似乎是模糊的。“如果delete操作数的值是空指针,则该操作无效”,然后,“如果delete表达式调用实现解除分配函数…”,然后,“delete表达式将调用解除分配函数”“。因此,要么它不能调用重载运算符,要么它未指定,要么它必须调用它。三个函数之一;-)@Hans:deallocation函数是实现运算符delete
的函数。这个术语来自这样一个事实:运算符出现在表达式中,而实现它们的函数是函数。换言之,您需要以某种方式分离术语。还要询问在分配零长度数组时调用运算符new
的原因:新测试[0]代码>…;)@ybungalobill:这更简单-标准要求返回的指针有效且不同。请注意,如果将析构函数设置为虚拟,则不会调用重载运算符delete
。实现通常直接从析构函数调用函数,并在不检查null的情况下调用析构函数(从而节省一些指令)。只有当调用需要虚拟分派时,才会提前执行检查。还有一件事:从析构函数调用操作符很方便,因为它保存了一个虚拟分派。