C++ delete 是否适用于指向基类的指针?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/294927/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does delete work with pointers to base class?
提问by Mark Ransom
Do you have to pass delete the same pointer that was returned by new, or can you pass it a pointer to one of the classes base types? For example:
您是否必须传递与 new 返回的指针相同的指针,还是可以传递一个指向类基类型之一的指针?例如:
class Base
{
public:
virtual ~Base();
...
};
class IFoo
{
public:
virtual ~IFoo() {}
virtual void DoSomething() = 0;
};
class Bar : public Base, public IFoo
{
public:
virtual ~Bar();
void DoSomething();
...
};
Bar * pBar = new Bar;
IFoo * pFoo = pBar;
delete pFoo;
Of course this is greatly simplified. What I really want to do is create a container full of boost::shared_ptr and pass it to some code that will remove it from the container when it is finished. This code will know nothing of the implementation of Bar or Base, and will rely on the implied delete operator in the shared_ptr destructor to do the right thing.
当然,这大大简化了。我真正想做的是创建一个充满 boost::shared_ptr 的容器,并将其传递给一些代码,以便在完成后将其从容器中删除。这段代码对 Bar 或 Base 的实现一无所知,并且将依赖于 shared_ptr 析构函数中隐含的删除操作符来做正确的事情。
Can this possibly work? My intuition says no, since the pointers will not have the same address. On the other hand, a dynamic_cast<Bar*> should work, so somewhere the compiler is storing enough information to figure it out.
这可能行得通吗?我的直觉说不,因为指针不会有相同的地址。另一方面, dynamic_cast<Bar*> 应该可以工作,所以编译器在某处存储了足够的信息来解决它。
感谢所有回答和评论的人的帮助。我已经知道虚拟析构函数的重要性,如我的示例所示;看到答案后,我想了想,意识到whole reason虚拟析构函数的全部原因就是这个确切的场景。因此它必须起作用。由于没有将指针转换回原始指针的可见方法,我感到很困惑。多一点思考让我相信有一种无形的手段,我推论析构函数正在返回真正的指针以供 delete 释放。当我在 ~Base 中看到这一行时,调查来自 Microsoft VC++ 的编译代码证实了我的怀疑:
mov eax, DWORD PTR _this$[ebp]
Tracing the assembler revealed that this was the pointer being passed to the delete function. Mystery solved.
跟踪汇编程序发现这是传递给删除函数的指针。谜团已揭开。
I've fixed the example to add the virtual destructor to IFoo, it was a simple oversight. Thanks again to everyone who pointed it out.
我已经修复了将虚拟析构函数添加到 IFoo 的示例,这是一个简单的疏忽。再次感谢所有指出这一点的人。
回答by Adam Rosenfield
Yes, it will work, if and only ifthe base class destructor is virtual, which you have done for the Base
base class but not for the IFoo
base class. If the base class destructor is virtual, then when you call operator delete
on the base class pointer, it uses dynamic dispatch to figure out how to delete the object by looking up the derived class destructor in the virtual function table.
是的,它会起作用,当且仅当基类析构函数是虚拟的时,您已经为Base
基类而不是基类做了这个IFoo
。如果基类析构函数是虚拟的,那么当您调用operator delete
基类指针时,它使用动态调度通过在虚函数表中查找派生类析构函数来确定如何删除对象。
In your case of multiple inheritance, it will only work if the base class you're deleting it through has a virtual destructor; it's ok for the other base classes to not have a virtual destructor, but only if you don't try to delete any derived objects via those other base class pointers.
在您的多重继承的情况下,只有当您删除它的基类具有虚拟析构函数时,它才会起作用;其他基类没有虚拟析构函数是可以的,但前提是您不尝试通过那些其他基类指针删除任何派生对象。
回答by Michael Burr
This doesn't relate to your given example, but since you mentioned that you're really interested in shared_ptr
's behavior when deleting its owned object, you might be interested in using shared_ptr
's 'deleter'.
这与您给定的示例无关,但是由于您提到shared_ptr
在删除其拥有的对象时您真的对' 的行为感兴趣,因此您可能对使用shared_ptr
'deleter'感兴趣。
If the object owned by the shared_ptr
needs special handling when being deleted, you can specify a 'deleter' for any particular shared_ptr<>
. The deleter is not part of the type, it's an attribute of a shared_ptr<>
instance, so your container of shared_ptr<>
objects could have some objects with different deleters. Here's what the Boost docs say about the shared_ptr<>
deleter:
如果该对象拥有的对象shared_ptr
在被删除时需要特殊处理,您可以为任何特定的shared_ptr<>
. 删除器不是类型的一部分,它是一个shared_ptr<>
实例的属性,因此您的shared_ptr<>
对象容器可能有一些具有不同删除器的对象。以下是 Boost 文档对shared_ptr<>
删除器的描述:
Custom deallocators allow a factory function returning a
shared_ptr
to insulate the user from its memory allocation strategy. Since the deallocator is not part of the type, changing the allocation strategy does not break source or binary compatibility, and does not require a client recompilation. For example, a "no-op" deallocator is useful when returning ashared_ptr
to a statically allocated object, and other variations allow ashared_ptr
to be used as a wrapper for another smart pointer, easing interoperability.
自定义释放器允许工厂函数返回 a
shared_ptr
以将用户与其内存分配策略隔离。由于解除分配器不是类型的一部分,因此更改分配策略不会破坏源代码或二进制兼容性,并且不需要客户端重新编译。例如,“无操作”解除分配器在将 a 返回shared_ptr
到静态分配的对象时很有用,其他变体允许将 ashared_ptr
用作另一个智能指针的包装器,从而简化互操作性。
It would be cleanest if you could modify IFoo
to have a virtual destructor since you're planning to delete objects that are subclasses of it through an IFoo
reference or pointer. But if you're stuck with an IFoo
that cannot be corrected, then if you want to use shared_ptr<IFoo>
in your container, but have it pointing to a Bar
, you could create the shared_ptr
instance with a deleter that performs a downcast to a Bar*
then does the delete operation. Downcasts are considered bad form, but this technique might be something that you could use in a bind.
如果您可以修改IFoo
为具有虚拟析构函数,那将是最干净的,因为您计划通过IFoo
引用或指针删除作为它的子类的对象。但是,如果您遇到IFoo
无法更正的 ,那么如果您想shared_ptr<IFoo>
在容器中使用,但将其指向 a Bar
,则可以shared_ptr
使用执行向下转换为 aBar*
的删除器创建实例,然后执行删除操作。Downcasts 被认为是不好的形式,但这种技术可能是你可以在绑定中使用的东西。