虚析构函数:基类是否需要动态分配内存?

时间:2012-09-07 14:30:44

标签: c++ virtual-destructor

此问题与Virtual destructor: is it required when not dynamically allocated memory?

中的讨论类似

在考试问题中,我被问到: - 维护指向动态分配内存的指针的任何基类应该定义什么?

我回答说: - 复制构造函数和赋值运算符(以确保不仅复制指针... c.f。深拷贝)和析构函数(释放已分配的内存)

他们说这不正确,因为这个基类也应该定义一个虚析构函数而不是普通的析构函数。为什么呢?

6 个答案:

答案 0 :(得分:6)

如果您的类打算以多态方式使用,那么您可能会指向指向派生对象的基类。

通过指向没有virtual析构函数的基类的指针删除派生对象会导致未定义的行为。这可能是她的推理。

5.3.5

  

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

答案 1 :(得分:5)

您的基类需要一个虚拟析构函数如果派生类的对象打算通过基类指针销毁,就像这样

Base *pointer_to_base_class = new Derived;
delete pointer_to_base_class;

从你的问题来看,目前还不清楚是否是这种情况。也许问题的另一部分(或前一个问题)明确表明这种多态破坏是有意的。或者,也许你在课堂上被教导总是期望将这种用作作为最佳实践。

答案 2 :(得分:5)

他们不是100%正确。虚拟析构函数是必须的

  1. 与动态多态和AND一起使用的类层次结构
  2. 派生对象通过指向base的指针销毁。
  3. 否则非虚拟析构函数就可以了。但是在大多数情况下,即使只有#1是预期的,无论#2如何,使析构函数变为虚拟都是一种很好的方式。

答案 3 :(得分:1)

在标准中,大多数继承层次结构都有一个虚拟析构函数;但是,sub_match被定义为公共继承自std::pair<BidirectionalIterator, BidirectionalIterator>,因此它可以拥有动态分配的内存。在相关区域中,match_results不是必需的,但通常实现为从std::vector<...>继承的公共继承,它肯定会分配内存。

您的审查员并非完全不正确,但对动态分配的内存的关注是一个红色的鲱鱼,并且背叛了该标准令人担忧的无知;而在大多数实现中,通过指向基类型而没有虚拟析构函数的指针来删除派生类型将导致破坏切片对象,根据标准它是未定义的行为。

答案 4 :(得分:0)

添加到其他答案:您还可以设想一种您确实需要公共基类的情况,但您没有任何实际的接口函数。但是如果你想要RTTI和动态强制转换支持,你需要在你的类中使用虚函数。析构函数可以就是那个函数。

例如,假设您是一名正在恢复的Java程序员并且坚持认为所有内容都是Object。你可以像这样开始你的第一个C ++程序:

class Object
{
public:
   virtual ~Object() { }
};

现在Object确实可以作为每个类的最终多态基类。

如果您还认为Object应该是抽象的,您甚至可以将析构函数设为纯虚拟:

class Object { public: virtual ~Object() = 0; }; Object::~Object() { }

答案 5 :(得分:0)

要在这里跟进所有好的答案,这是一个很好的做法,声明一个虚拟析构函数,以确保在一个类被子类化以形成层次结构并且你想要的时候进行适当的清理通过指向它的指针删除派生对象。 C ++标准很清楚:

  

当您想通过基类删除派生类对象时   指针和基类的析构函数不是虚拟的   结果未定义

通过未定义的行为,您可以想到内存泄漏,例如,如果派生类分配了一些动态内存,并且您尝试稍后通过此基类删除它。你的老师可能正在考虑这种情况。