为什么删除操作符要求是静态的?
我发现这个问题提出了同样的问题事情,但是只回答了“新”部分,所以这里又来了。
为什么删除操作符要求是静态的?无论如何,这没有意义。 new 运算符非常有意义,就像构造函数不能是虚函数一样,new 运算符也不能是虚函数。但是,当您使用继承时,析构函数可以(并且应该)是虚拟的,以便允许销毁(通过多态性)用作基类的对象。
据我所知,当调用删除运算符时,该对象已经被销毁,因此不存在“this”。然而,使用与虚拟析构函数相同的推理,让删除运算符与创建对象的新运算符相匹配仍然有意义。
这就是我现在的意思,
class A
{
public:
virtual ~A() {}
};
class B : public A
{
public:
void* operator new (size_t sz);
void operator delete (void* ptr, size_t sz);
};
如果我们执行
A *ptr = new B();
delete ptr; // <-- fail
A 的删除运算符(默认)应该被调用,因为它是静态的,并且在编译时不知道(除了这里的微不足道的情况之外)哪个删除运算符是正确的。
但是,我用上面的代码制作了一个小型测试程序(仅在 new/delete 运算符中使用 malloc/free,在删除中使用 print 语句),并使用 g++ 对其进行编译。运行它非常意外地在 B 的删除运算符中产生了输出。
我的(真正的)问题是这样的:删除运算符是否存在一些隐式的“虚拟性”?它只是在无 this 指针的意义上是静态的吗?或者这只是 g++ 的一个功能?
我开始研究 C++ 规范,但我必须承认,我对它有点不知所措,所以任何帮助都很感激。
I found this one question asking the same thing, however only the 'new' part was answered, so here goes again.
Why is the delete operator required to be static? Somehow it doesn't make sense. The new operator makes perfect sense, just like the constructor can't be virtual, neither can the new operator. However, the destructor can (and should) be virtual when you use inheritance, in order to allow destruction of objects being used (by way of polymorphism) as a base class.
I understand that, when the delete operator is called, the object has already been destroyed, so no 'this' exists. Yet it still makes sense, using the same reasoning as with virtual destructor, to have the delete operator match the new operator which created the object.
This is what I mean
class A
{
public:
virtual ~A() {}
};
class B : public A
{
public:
void* operator new (size_t sz);
void operator delete (void* ptr, size_t sz);
};
now if we do
A *ptr = new B();
delete ptr; // <-- fail
A's delete operator (default) should've been called, since it's static and it's not known (for anything but the trivial case here) at compile time which delete-operator is the correct one.
However, I made a small test program with the code above (just malloc/free in the new/delete operators, and print statement in delete), and compiled it using g++. Running it quite unexpectedly produced the output in B's delete operator.
My (real) question is this: Is there some implicit 'virtualness' to the delete operator? Is it only static in the no-this-pointer sense? Or is this just a g++ feature?
I started looking through the C++ specification, but I must admit, I was bit overwhelmed by it, so any help appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
语言规则中的答案实际上是在 12.5 [class.free] 中。
如果您通过指向基类的指针进行删除,则析构函数必须是虚拟的,否则您会得到未定义的行为。否则,实现必须确定要删除的对象的动态类型。
12.5/4 说,当
delete
没有以::
为前缀时,则通过在上下文中查找delete
来确定释放函数动态类型的虚拟析构函数。这确保了类似虚拟的查找,即使operator delete
始终是static
成员函数。原始分配和释放在概念上发生在对象的生命周期之外,因此当调用释放函数时,不再有对象提供虚拟查找机制,但查找规则确保
操作符删除
有一个动态(virtual-lite!)查找机制。这意味着删除操作符可以明智地是静态的,而不会失去与原始对象的动态类型的联系。The answer in the language rules is really in 12.5 [class.free].
If you are deleting via a pointer to a base class then the destructor must be virtual or you get undefined behaviour. Otherwise, the implementation has to determine the dynamic type of the object being deleted.
12.5/4 says that when the
delete
isn't prefixed by::
then the deallocation function is determined by looking updelete
in the context of the dynamic type's virtual destructor. This ensures virtual-like lookup, even thoughoperator delete
is always astatic
member function.Raw allocation and deallocation happen conceptually outside of the object's lifetime so by the time the deallocation function is to be called, there is no longer an object to provide a virtual lookup mechanism but the lookup rules ensure that
operator delete
has a dynamic (virtual-lite!) lookup mechanism. This means that operator delete can sensibly bestatic
without losing touch with the original object's dynamic type.delete
运算符仅用于释放内存,并且为整个派生类对象释放内存 - 在一个操作中 - 与new
运算符完全相同为整个最派生类对象分配 - 作为参数传递到 new Class 构造中的类对象。这就是为什么当您执行
delete ptr;
操作时,delete
运算符始终仅针对要删除的对象的实际最派生类以及该类的数据调用一次如果存在虚拟析构函数,则从 vtable 推断;如果没有虚拟析构函数,则从指针的类型推断。这就是为什么删除操作符没有隐式虚拟性 - 所有虚拟性都在析构函数调用时结束。delete
operator is for deallocating memory only, and memory is deallocated for the most derived class object as a whole - in one action - exactly the same way as withnew
operator it is allocated for the whole most-derived class object - the object of class passed as argument intonew Class
construct.This is why when you do
delete ptr;
thedelete
operator is always called only once for the actual most-derived class of the object being deleted and the data on what class it is is deduced from either the vtable if the virtual destructor is present or the type of the pointer if there's no virtual destructor. That's why there'no implicit virtualness to thedelete
operator - all virtualness ends at the point of destructor call.