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的情况下调用析构函数(从而节省一些指令)。只有当调用需要虚拟分派时,才会提前执行检查。还有一件事:从析构函数调用操作符很方便,因为它保存了一个虚拟分派。