【问题标题】:Error: "pointer being freed was not allocated" produced concerning the virtual destructor错误:关于虚拟析构函数产生“未分配指针”
【发布时间】:2014-11-28 02:36:48
【问题描述】:

这是产生错误的程序:

#include <iostream>
#include <string>
using namespace std;

class Pet {
protected:
    string name;
public:
    Pet(string nam):name(nam){}
    ~Pet(){cout<< "Pet destroyed" << endl;} // attention
    void play();
};

void Pet::play(){
    std::cout<< "Pet " << name <<" is playing ..." <<endl;
}

class Cat : public Pet {
public:
    Cat(string nam):Pet(nam){}
    ~Cat(){cout<< "Cat destroyed" <<endl;}
    void play();
};

void Cat::play(){
    cout<< "cat " << name <<" is playing ..." <<endl;
}

class Dog : public Pet {
public:
    Dog(string nam):Pet(nam){}
    ~Dog(){cout<< "Dog destroyed" <<endl;}
    virtual void play(); // attention
};

void Dog::play(){
    cout<< "dog " << name <<" is playing ..." <<endl;
}

int main(void) {
    Pet *cat1 = new Cat("Kitty");
    Pet *dog1 = new Dog("Tom");
    Pet *pet = new Pet("Nicky");

    cat1->Pet::play();
    dog1->play();
    pet->play();

    delete cat1;
    delete pet;
    delete dog1;
    return 0;
}

这个程序编译得很好,但是当我运行它时,我得到了以下输出:

Pet Kitty is playing ...
Pet Tom is playing ...
Pet Nicky is playing ...
Pet destroyed
Pet destroyed
Pet destroyed
t(35634,0x7fff7ae04310) malloc: *** error for object 0x7f8623c03b68: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

错误信息之前的结果很有意义,但我不明白为什么会出现这个错误。错误在delete dog1; 行产生。 0x7f8623c03b68 是对象 dog1 的地址。由于dog1-&gt;play(); 执行得很好,所以应该很好地分配对象dog1 的内存空间。为什么错误提示“未分配指针被释放”???

当我将类 Pet 的析构函数更改为虚拟时,程序执行良好,没有错误。为什么???这是输出:

Pet Kitty is playing ...
Pet Tom is playing ...
Pet Nicky is playing ...
Cat destroyed
Pet destroyed
Pet destroyed
Dog destroyed
Pet destroyed

在这种情况下,删除 dog1 时,会先调用 Dog 的析构函数,然后调用 Pet 的析构函数。那么在这两种情况下,“虚拟”这个词对内存的变化有什么不同呢?

在这篇文章中 Why should I declare a virtual destructor for an abstract class in C++? 它解释了当基类的析构函数未声明为虚拟时,当删除引用子类对象的基类类型的指针时,将产生未定义的行为。那么这个错误只是所谓的未定义行为的一个例子吗?自从我从 Dog 类中删除虚拟后,程序运行良好。

我注意到这是否与上述文章中提到的问题相同。只是想确定并找到该错误的原因。

欢迎任何指示。谢谢。

【问题讨论】:

    标签: c++ memory-management virtual


    【解决方案1】:

    delete cat1; 行导致未定义的行为,因为cat1 的类型为Pet *,但是Pet 没有虚拟析构函数,并且指针实际上指向派生类的实例。

    当行为未定义时,任何事情都可能发生。如您所述,要解决此问题,您需要 virtual ~Pet()

    我猜 malloc 错误将与 Dog 的类布局有关:Dog 需要一个 vtable,因此可能分配了一个更大的区域,该区域的开始地址与 dog 不同。 (熟悉 vtable 布局的人可能会证实这一点)

    【讨论】:

      【解决方案2】:

      When I change the destructor of class Pet to be virtual, the program executes fine without errors. Why???

      因为标准只有在析构函数是虚拟的时候才能保证正确的行为:

      5.3.5 删除

      1. 在第一种选择(删除对象)中,如果 操作数与其动态类型不同,静态类型应为操作数动态类型的基类,且静态类型应具有虚拟析构函数 或行为未定义

      【讨论】:

        猜你喜欢
        • 2013-11-01
        • 2018-03-18
        • 2016-01-08
        • 1970-01-01
        • 2017-01-13
        • 2020-12-27
        • 1970-01-01
        • 1970-01-01
        • 2012-10-24
        相关资源
        最近更新 更多