【问题标题】:Missing Virtual Destructor Memory Effects缺少虚拟析构函数记忆效果
【发布时间】:2015-10-18 06:52:14
【问题描述】:

根据标准,缺少虚拟析构函数的多态性会导致未定义的行为。实际上,它确实导致在删除父类时没有调用派生类的析构函数。但是,它是否也会导致任何常见编译器/系统中的内存泄漏?我对 Android/Linux 上的 g++ 特别感兴趣。

具体来说,我指的是删除内存派生类是否会以某种方式泄漏。考虑:

class Base {}
class Derived {
    int x;
}

如果我将Base* 删除为Derived,会泄漏4 个字节吗?或者内存分配器是否已经知道根据分配要释放多少字节?

【问题讨论】:

  • “缺少虚拟析构函数的多态性会导致未定义的行为。”它不必。仅当您从基指针对派生对象调用 delete 时才会出现问题。
  • @CamelToe 不,我没有,但是有一些预先存在的代码,除非确实存在问题,否则我不想修复它。另外,我比什么都好奇。

标签: android c++ virtual


【解决方案1】:

当然可以。考虑:

class A
{
public:
 virtual void func() {}
};

class B : public A
{
public:
   void func() { s = "Some Long String xxxxxx"; }
private:
   std::string s;
   // destructor of B will call `std::string` destructor.
};

A* func(bool b)
{
   if (b)
       return new B;
   return new A;
}

... 
   A* a = func(true);
...
   delete a;

现在,这将造成内存泄漏,因为 B 对象中的 std::string s 不会被 A::~A 释放 - 您需要调用 B::~B,这只会在析构函数是虚拟的情况下发生。

请注意,这适用于我所知道的所有编译器和所有运行时系统(这是所有常见的和一些不太常见的)。

编辑:

基于更新后的实际问题:内存取消分配是根据分配的大小发生的,因此,如果您可以保证不会因为类的构造/使用而发生单一分配,那么不存在是安全的一个虚拟析构函数。但是,如果基类的“客户”可以制作他/她自己的扩展类,这会导致有趣的问题。将派生类标记为final 将防止它们被进一步派生,但如果基类在其他人可以包含的头文件中可见,那么您将冒有人从Base 派生他们自己的类的风险。分配。

因此,换句话说,在PImpl 之类的东西中,Impl 类隐藏在没有其他人从中派生的源文件中,拥有它是合理的。对于大多数其他情况,这可能是个坏主意。

【讨论】:

  • 很好的答案,但不是我正在寻找答案的问题。我已经更新了我的问题以澄清。
  • @IanPudney:更新了答案。
【解决方案2】:

缺少析构函数会导致未定义的行为,特别是因为编译器无法确切知道副作用可能是什么。

将其视为 RAII 的清理方面。在这种情况下,如果您声称自己清理过,但仍设法不清理,则副作用可能是:

  • 内存泄漏(你分配了一些东西......你现在什么时候释放它?)
  • 死锁(你锁定了一些东西……你现在什么时候解锁?)
  • 套接字保持打开状态(您曾经打开过它...但现在什么时候关闭它?)
  • 文件保持打开状态(您曾经打开过...但现在什么时候刷新?)
  • 访问无效的指针(例如,您更新了指向某个成员的指针...但现在何时取消设置?)
  • 您的硬盘驱动器被擦除(从技术上讲,这是对任何未定义行为的有效答案)

【讨论】:

  • 相信我,我很清楚“未定义行为”的含义,但我正在寻找特定系统上的实用行为。
  • 实际的行为是不值得麻烦尝试优化掉给定的析构函数。我怎么强调都不过分。我知道没有任何现代硬件,无论是移动设备还是其他设备,为绕过标准而奋斗的麻烦是值得您获得的收益的。如果你那个有限,那么我建议你改用纯C。
【解决方案3】:

这应该会导致未定义的行为,这意味着它也可能导致内存泄漏。在 delete 的 5.3.5/3 (n4296 c++14) 中,您有:

在第一种选择(删除对象)中,如果要删除的对象的静态类型与其不同 动态类型,静态类型应该是要删除的对象的动态类型的基类, 静态类型应具有虚拟析构函数,否则行为未定义。在第二种选择中(删除 array) 如果要删除的对象的动态类型与其静态类型不同,则行为未定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-01
    • 2013-07-06
    • 2011-08-12
    • 2012-04-13
    • 2012-04-18
    • 2017-03-16
    • 2012-12-20
    • 2014-11-04
    相关资源
    最近更新 更多