我遇到的问题是,据我所知,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 * );
如果以上是标准行为?
答案 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)