为什么C++子类中的字符串会导致内存泄漏?

Leo*_*ang 5 c++ memory-leaks

我花了2个多小时发现这个内存泄漏:

class Parent{
  ...
}

class Child:public Parent{
  std::string str;
  ...
}

int main(){
  Parent *ptr=new Child();
  delete ptr;
}
Run Code Online (Sandbox Code Playgroud)

我通过将字符串移动到父类来修复它.为什么会发生内存泄漏?孩子的成员不应该被删除吗?

Tas*_*Tas 11

这可能发生,因为Parent可能没有虚拟析构函数.由于您正在Parent*为动态分配的派生类创建(基类)Child,因此删除Parent*没有虚拟析构函数的行将导致未定义的行为,但通常会导致派生类未被销毁.

来自Scott Myers - Effective C++第三版:

...如果我们使用非虚拟析构函数删除基类指针,则结果是未定义的.通常在运行时发生的是对象的派生部分永远不会被销毁.这是泄漏资源,破坏数据结构以及花费大量时间使用调试器的绝佳方法.所以任何具有虚函数的类几乎都应该有一个虚析构函数.

class Parent{
};

class Child:public Parent{
public:
    Child() : str("Child") {}
    ~Child() { std::cout << str << std::endl;};
    std::string str;
};

int main(){
    Parent *ptr=new Child();
    delete ptr; // undefined behaviour: deleting a Base* to a Derived object where the Base has no virtual destructor
}
Run Code Online (Sandbox Code Playgroud)

你可以通过制作Parent析构函数来解决这个问题virtual:

class Parent{
public:
    virtual ~Parent() {} // Will call derived classes destructors now as well
};

class Child:public Parent{
public:
    Child() : str("Child") {}
    ~Child() { std::cout << str << std::endl;};
    std::string str;
};

int main(){
    Parent *ptr=new Child();
    delete ptr;
    // Child::~Child() has now been called.
}
Run Code Online (Sandbox Code Playgroud)

请参阅何时使用虚拟析构函数?这可能比我更好地解释了它

编辑:感谢@aschepler(在问题的评论中),下面的评论者,以及链接问题的答案,我更新了答案,以更好地反映这是未定义的行为.在我的匆忙中,我没有提到它,只提到了典型的行为

  • 实际上,根据C++标准,使用基类指针删除派生对象是未定义的行为,并且基类的析构函数不是虚拟的. (3认同)