【问题标题】:Why is "operator delete" invoked when I call "delete" on a null pointer?当我在空指针上调用“delete”时,为什么会调用“operator delete”?
【发布时间】:2011-04-18 19:44:13
【问题描述】:

在阅读this question 的答案时,我注意到答案(例如this)暗示即使在delete 语句在空指针上执行时也可以调用operator delete

于是我写了一个小sn-p:

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呢?

【问题讨论】:

  • 还问为什么在分配零长度数组时会调用operator newnew Test[0];... ;)
  • @ybungalobill:这更容易 - 标准要求返回的指针有效且不同。
  • 请注意,如果将析构函数设为虚拟,则不会调用重载operator delete。实现通常直接从析构函数调用函数并调用析构函数而不检查空值(从而节省了一些指令)。只有当呼叫需要虚拟调度时,才会提前进行检查。
  • 还有一点:从析构函数中调用操作符很方便,因为它节省了一次虚拟调度。

标签: c++ pointers memory-management


【解决方案1】:

即将发布的 C++0x 标准(第 5.3.5 节 [expr.delete])中的语言如下:

如果操作数的值 删除表达式不为空 指针值,删除表达式 将调用释放函数 (3.7.4.2)。否则就是 未指定是否解除分配 函数将被调用。 [注: 调用释放函数 不管是否有析构函数 对于对象或某些元素 数组抛出异常。 ——尾注]

所以这是未指定的行为,一些编译器可能会在删除 NULL 指针时调用operator delete,而其他编译器可能不会。

编辑:标准使用的术语 deallocation function 似乎引起了一些混乱。它带有参考。 3.7.4.2 [basic.stc.dynamic.deallocation] 中的一些关键语言可能有助于澄清:

如果一个类 T 有一个名为 operator delete 的成员释放函数 只有一个参数,那么该函数就是一个通常的(非放置)释放函数。

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

价值 提供给释放函数的第一个参数可以是空指针值;如果是这样,如果释放 函数是标准库中提供的,调用无效。

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

【讨论】:

  • 嗯,这个sn-p说的是deallocation函数,不是operator。
  • C++03 在这个问题上似乎含糊不清。它说“如果 delete 的操作数的值是空指针,则操作无效”,然后,“如果 delete-expression 调用实现释放函数......”,那么,“delete-expression 将调用一个释放函数”。所以要么它不能调用重载的操作符,要么它是未指定的,要么它必须调用它。三者之一;-)
  • @Hans:释放函数是实现operator delete的函数。这个术语来自这样一个事实,即运算符出现在表达式中,而实现它们的函数函数。换句话说,您需要以某种方式分离您的术语。
【解决方案2】:

操作符 delete 和其他操作符一样,为什么不调用呢?它不能在被调用之前检查它的参数。

这就像问为什么在添加 0 时会调用 operator+

【讨论】:

  • delete 语句不只是调用operator delete,它首先调用析构函数,并且在调用析构函数之前必须进行空值检查(因此在调用operator delete 之前)。 operator delete 不像其他运算符重载。
  • 好的,但是编译器无法确保在给定空指针时用户定义的运算符 delete 是空操作。例如,它可以记录表明您试图删除空指针的内容。
  • 同意Ben Voigt:当你输入delete p;时,编译器首先调用对象的析构函数,然后调用释放函数operator delete。系统必须能够诊断出指针为 0,以避免调用析构函数(它不会调用),因此从技术上讲,它也可以避免调用释放器。
  • 实际上,C++ 标准明确允许编译器避免使用空指针值调用operator delete
猜你喜欢
  • 1970-01-01
  • 2018-10-21
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 2014-09-24
  • 2014-10-09
相关资源
最近更新 更多