This question already has answers here:
When to use virtual destructors?

(17个答案)


2年前关闭。




我花了几个小时试图弄清楚问题出在哪里,但似乎太奇怪了。

我用一种更容易理解的方式重写了我的问题。

当到达说删除的行时,debbug会产生一个断点。

附言值得一提的是,如果我们将int b1移到Base2上,它将可以正常工作。

Base1:
#pragma once
class Base1
{
public:
    Base1();
    ~Base1();
    int b1;
};

Base2.h:
#pragma once
#include <iostream>
#include <vector>
class Derived;
class Base2
{
public:
    Base2();
    ~Base2();
    std::vector <std::vector <Base2*>> vec;
    void doSomething(Derived& d);
};

Base2.cpp:
#include "Base2.h"
#include "Derived.h"


Base2::Base2()
{
    //the numbers 1 and 5 does not really metter
    vec.resize(1);
    vec[0].resize(5);
}


Base2::~Base2()
{
}

void Base2::doSomething(Derived& d)
{
    vec[0][d.b1] = new Derived();
    delete vec[0][d.b1];
}

衍生的:
#pragma once
#include "Base1.h"
#include "Base2.h"
class Derived : public Base1, public Base2
{
public:
    Derived();
    ~Derived();
};

主要的:
#include <iostream>
#include "Derived.h"

int main()
{
    Derived d;
    d.b1 = 1;
    d.doSomething(d);
}

最佳答案

Base2缺少虚拟析构函数。

通过指向基础对象的指针删除派生对象,如果该基础对象没有虚拟析构函数,则会导致未定义的行为。

通常,这种UB仅导致丢失析构函数调用(并因此导致内存/资源泄漏),但是在这种情况下,由于涉及多个继承,因此情况有所不同。

new Derived()返回的指针转换为Base2 *时,指针的数值会更改(由于多重继承)。

delete调用~Base2()之后,它随后将指针传递给内存释放函数。
释放函数期望使用与new返回的地址相同的地址,该地址是整个Derived实例的地址。取而代之的是,它获得了Base2子对象的地址,该地址是不同的(同样,由于多重继承)。

这与其他任何“没有通过delete返回的指针使用new”情况没有什么不同,通常会导致崩溃。

如果Base2具有虚拟析构函数,则将在释放之前将指针调整为指向Derived的整个实例。

09-25 20:27
查看更多