如何在C ++中覆盖删除行为?

时间:2009-01-02 22:36:03

标签: c++ memory

我遇到的问题是,据我所知,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 :: operator delete。这似乎正在发生,因为当定义析构函数时,编译器会将名为“标量删除析构函数的函数插入 vtable ”。然后该函数将调用Derived::delete

所以我有问题: 1)这是标准行为吗? 2)我什么时候应该使用

void operator delete( void *, size_t );

VS

void operator delete( void * );

如果以上是标准行为?

2 个答案:

答案 0 :(得分:8)

肯定是标准行为。如果使用派生类的operator new,也将使用 运算符delete(也请注意,即使您没有明确告诉编译器这些函数是静态的,它们 是隐式的宣布如此)。可能存在一个顽皮的情况,即派生类中有一个operator new,但相应的operator delete在基类中。我认为这是有效的,但我会避免这种情况。依赖于基本运算符删除,同时在派生类中定义自己的运算符new将不可避免地造成麻烦。

  

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

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

  

我应该何时使用void operator delete(void *,size_t);

如果您希望在运算符delete中分配已知的大小。我写了这里的含义: What does the C++ new operator do other than allocation and a ctor call?。如果你使用(来自你的重载成员运营商删除/新)全球运营商new&删除以获取内存并释放它,甚至malloc / free,您不需要这些大小信息。但它可能对记录目的很有用。

答案 1 :(得分:6)

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

以下是标准的相关摘录:

1 delete-expression运算符会销毁大多数派生对象   ( intro.object )或由new-expression创建的数组。           删除表达式:                   :: opt删除cast-expression                   :: opt delete [] cast-expression   第一种方法是非数组对象,第二种方法是   阵列。操作数应具有指针类型或具有的类类型   单个转换函数( class.conv.fct )到指针类型。   结果类型为void。

3在第一个备选(删除对象)中,如果是静态类型   操作数与其动态类型不同,静态类型应为a   操作数的动态类型的基类和静态类型   有一个虚拟析构函数或行为未定义。在第二个   替代(删除数组)如果要对象的动态类型   删除与其静态类型不同,行为未定义.19)