2010-09-29 78 views
16

在阅读this question的答案时,我注意到答案(例如this)意味着即使delete语句在空指针上执行时也可以调用operator delete为什么当我在空指针上调用“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++负责处理这个问题。那么为什么在这种情况下调用operator delete

+0

问一下为什么当你分配零长度数组时,调用operator new:'new Test [0];'...;) – ybungalobill 2010-09-29 13:37:44

+1

@ybungalobill:这很简单 - 标准要求返回的指针是有效的且不同的。 – sharptooth 2010-09-29 14:08:10

+0

请注意,如果您使析构函数为虚拟,则不会调用重载'operator delete'。实现通常直接从析构函数调用该函数,并在不检查null的情况下调用析构函数(从而节省一些指令)。只有当呼叫需要虚拟调度时才是预先执行的检查。 – avakar 2010-09-29 14:11:10

回答

18

在即将到来的C++ 0x标准的语言(第5.3.5节[expr.delete])被调用如下:

如果 的操作数的值不是空指针值 ,则删除表达式 将调用释放函数 (3.7.4.2)。否则,未指定 函数是否会调用释放 函数。 [注意: 解除分配函数称为 ,不管对象的析构函数 还是 数组的某个元素都引发异常。 - 注完]

所以它是不确定的行为,一些编译器可以调用operator delete当NULL指针被删除,其他人可能不会。

编辑:术语释放函数使用的标准似乎是造成一些混淆。它带有一个参考。从3.7.4.2 [basic.stc.dynamic.deallocation]一些关键的语言可能有助于澄清:

如果一个类T有一个名为operator delete 恰好与一个参数一个成员释放功能,该功能是通常(非配置)释放的功能。

该标准也很清楚的是用户定义operator delete需要接受一个参数,该参数是一个空指针值:

的 第一个参数的供应给释放函数的值可以是一个空指针值;如果是这样,并且如果释放 函数是标准库中提供的函数,则该调用不起作用。

但由于未指定的行为5.3.5,当指针为空时,不应该依赖于您调用的operator delete

+0

嗯,这个片段谈论的是释放功能,而不是操作员。 – 2010-09-29 13:36:29

+0

C++ 03在这个问题上似乎含糊不清。它说“如果删除操作数的值是空指针操作 没有效果”,那么,“如果删除表达式调用 执行释放函数...”,那么“删除表达式将调用一个释放函数“。所以要么不能调用重载操作符,要么没有指定,或者必须调用它。其中之一;-) – 2010-09-29 13:40:40

+0

@Hans:释放函数是实现'operator delete'的函数。这个术语来自于操作符出现在表达式中的事实,而实现它们的函数是*函数。换句话说,你需要以某种方式分离你的术语。 – ybungalobill 2010-09-29 13:41:26

10

运算符删除就像任何其他运算符一样,为什么它不被调用?在调用之前,它无法检查其参数

这就好比问为什么operator+当你添加0

+10

'delete'语句不只是调用'operator delete',它首先调用析构函数,并且在调用析构函数之前(因此在调用'operator delete'之前)必须执行一个空的检查。 'operator delete'不像其他的操作符重载。 – 2010-09-29 13:12:55

+0

好的,但编译器无法确定在给定空指针时用户定义的操作符delete是否为空操作。例如,它可以记录表明你试图删除空指针的东西。 – 2010-09-29 13:16:32

+2

同意Ben Voigt:当你键入'delete p;'时,编译器首先调用对象的析构函数,然后调用释放函数'operator delete'。系统必须能够诊断指针为0,以避免调用析构函数(它不会调用它),所以在技术上它也可以避免调用deallocator。 – 2010-09-29 13:19:42

相关问题