代码之家  ›  专栏  ›  技术社区  ›  BigSandwich

在C++中重写delete应该如何表现?

  •  9
  • BigSandwich  · 技术社区  · 17 年前

    我遇到的问题是,据我所知,delete运算符应该是一个静态函数,但有时编译器(VC++)似乎将其视为动态函数。

    鉴于:

    class Base
    {
    public:
      void* operator new(size_t size) { /* allocate from custom heap */ }
      void operator delete(void *p) { customFree(p, sizeof(Base)); }
    
      Base() {}
      virtual ~Base() {}
    };
    
    class Derived: public Base
    {
    public:
      void* operator new(size_t size) { /* allocate from custom heap */ }
      void operator delete(void *p) { customFree(p, sizeof(Derived)); }
    
      Derived() {}
      virtual ~Derived() {}
    }
    

    我看到的情况是,删除基指针将导致调用 Derived::opeator 删除。

    Base *p = new Derived();
    delete p; //calls Derived::operator delete
    

    如果我不定义任何 析构器 然后我得到了预期的结果:调用了Base::运算符delete。这似乎是因为编译器正在插入一个名为“标量删除”的函数 析构函数 进入 函数表 当a 析构函数 定义。然后,该函数将调用 Derived::delete .

    所以我不得不问: 1) 这是标准行为吗? 2) 我什么时候用

    void operator delete( void *, size_t );
    

    vs。

    void operator delete( void * );
    

    如果上述行为是标准行为?

    2 回复  |  直到 11 年前
        1
  •  8
  •   Community Mohan Dere    9 年前

    这当然是标准行为。如果使用了派生类的运算符new, 它的 运算符delete也将被使用(另请注意,即使您没有明确告诉编译器这些函数是静态的,它们 是 隐含地声明了这一点)。可能会出现这样一种情况,即派生类中有一个运算符new,但相应的运算符delete在基类中。我认为这是有道理的,但我会避免这样做。依赖于基运算符delete,同时在派生类中定义自己的运算符new将不可避免地造成麻烦。

    如果我没有定义任何析构函数,那么我就会得到我预期的结果:

    你会得到未定义的行为:)一切都有可能发生,包括你(错误地)期望的事情。通过指向另一种类型对象的基指针进行删除需要虚拟析构函数。隐式声明的析构函数不是虚的。

    何时应该使用void运算符delete(void*,size_t);

    如果你想让操作符中已知的分配大小被删除。我在这里写下了它的含义: What does the C++ new operator do other than allocation and a ctor call? 。如果您使用(在重载成员运算符delete/new中)全局运算符new&delete以获取内存并释放它,甚至malloc/free,你不需要那个大小信息。但它可能对日志记录有用。

        2
  •  6
  •   user3458 user3458    17 年前

    (嘿,我应该先发帖,稍后再查:)

    以下是本标准的相关摘录:

    1 delete表达式运算符会破坏一个 最衍生对象 ( 介绍对象 )或由新表达式创建的数组。 删除表达式: ::选择删除强制转换表达式 ::opt-delete[]强制转换表达式 第一种选择是针对非数组对象,第二种是针对 阵列。操作数应具有指针类型,或具有以下属性的类类型 单一转换函数( class.conv.fct )转换为指针类型。 结果的类型为void。

    3在第一种选择(删除对象)中,如果静态类型 操作数与其动态类型不同, 静态类型应为 操作数的动态类型和静态类型的基类应 具有虚拟析构函数或行为未定义。 第二 如果对象的动态类型为 delete与其静态类型不同,行为未定义。19)