【问题标题】:In what cases the virtual base destructor can still go uncalled causing memory leaks?在什么情况下,虚拟基础析构函数仍然可以未被调用,从而导致内存泄漏?
【发布时间】:2013-04-02 00:37:38
【问题描述】:

有一个基类Heap 和两个派生类MinHeapMaxHeap - 如下所示:

我创建了一个派生类对象:

MinHeap* myminheap = new MinHeap();

但使用删除它

delete myminheap;

有/无 virtual ~Heap() {} 给我 glibc 内存泄漏错误! 症结是什么? 我已经浏览了很多关于这个的帖子.....

Overriding operator new/delete in derived class

Why base class destructor (virtual) is called when a derived class object is deleted?

memory leak when deleting derived class with base-class pointer

....但我不明白为什么设置基本析构函数 virtual 仍然会导致内存错误?

Heap* h_ptr = myminheap;
delete h_ptr;

ps。做 ^ 事情是不可能的,我无法将派生类对象指针类型转换为基指针,因为会弹出以下错误

‘class Heap’ has no member named ‘insert’
‘class Heap’ has no member named ‘pop_min'

我可以通过在 Heap 类中引入它们来处理

后来,我意识到,如果我调用free(h_ptr);,而不是调用delete h_ptr;,我不会受到内存泄漏的影响.. 万岁!但我需要对这种行为有所了解!

堆.h

#include <cstdlib>
#include <vector>
#include <iterator>

using namespace std;

class Heap
{
  public:
    Heap() {}
    ~Heap() {}

    vector <int> heap;
    int left(int parent);
    int right(int parent);
    int parent(int child);
    int size()                  {return heap.size();}
    virtual void insert(int element) {}
    virtual int pop_min() {}
    virtual int pop_max() {}
    void print();
};

class MinHeap : public Heap
{
  private:
    void heapify_up(int index);
    void heapify_down(int index);

  public:
    MinHeap() {}
    ~MinHeap() {}

    int pop_min();
    void insert(int element);
};

class MaxHeap : public Heap
{
  private:
    void heapify_up(int index);
    void heapify_down(int index);

  public:
    MaxHeap() {}
    ~MaxHeap() {}

    int pop_max();
    void insert(int element);
};

堆.cc

#include <cstdlib>
#include <iostream>
#include <vector>
#include <iterator>

using namespace std;

#include "heap.h"

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int Heap::left(int parent)
{
    int i = (parent << 1) + 1;  //2 * parent + 1    read more on bit shifts
    return (i < heap.size()) ? i : -1;
}

int Heap::right(int parent)
{
    int i = (parent << 1) + 2;
    return (i < heap.size()) ? i : -1;
}

int Heap::parent(int child)
{
    if(child){
        int i = (child >> 1) - 1;
        return i;
    }
    else return -1;
}

void Heap::print()
{
    vector<int>::iterator i = heap.begin();
    cout << "Heap = ";
    while(i != heap.end()){
        cout << *i << " ";
        i++;
    }
    cout << endl;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int MinHeap::pop_min()
{
    int min = heap.front();
    heap[0] = heap[heap.size() - 1];
    heap.pop_back();
    heapify_down(0);
    return min;
}

void MinHeap::insert(int element)
{
    heap.push_back(element);
    heapify_up(heap.size() - 1);
}

void MinHeap::heapify_up(int index)
{
    while(index > 0 && parent(index) >= 0 && heap[parent(index)] > heap[index]){
        int temp = heap[index];
        heap[index] = heap[parent(index)];
        heap[parent(index)] = temp;
        index = parent(index);
    }
}

void MinHeap::heapify_down(int index)
{
    int child = left(index);

    if(child > 0 && right(index) > 0 && heap[child] > heap[right(index)])
        child = right(index);

    if(heap[index] > heap[child]){
        int temp = heap[child];
        heap[child] = heap[index];
        heap[index] = temp;
        heapify_down(child);
    }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int MaxHeap::pop_max()
{
    int max = heap.front();
    heap[0] = heap[heap.size() - 1];
    heap.pop_back();
    heapify_down(0);
    return max;
}

void MaxHeap::insert(int element)
{
    heap.push_back(element);
    heapify_up(heap.size() - 1);
}

void MaxHeap::heapify_up(int index)
{
    while(index > 0 && parent(index) >= 0 && heap[parent(index)] < heap[index]){
        int temp = heap[index];
        heap[index] = heap[parent(index)];
        heap[parent(index)] = temp;
        index = parent(index);
    }
}

void MaxHeap::heapify_down(int index)
{
    int child = left(index);

    if(child > 0 && right(index) > 0 && child < right(index))
        child = right(index);

    if(heap[index] < heap[child]){
        int temp = heap[child];
        heap[child] = heap[index];
        heap[child] = temp;
        heapify_down(child);
    }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//              test program
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main(){
    // Create the heap
    MinHeap* myminheap = new MinHeap();
    myminheap->insert(700);
    myminheap->print();
    myminheap->insert(500);
    myminheap->print();
    myminheap->insert(100);
    myminheap->print();
    myminheap->insert(800);
    myminheap->print();
    myminheap->insert(200);
    myminheap->print();
    myminheap->insert(400);
    myminheap->print();
    myminheap->insert(900);
    myminheap->print();
    myminheap->insert(1000);
    myminheap->print();
    myminheap->insert(300);
    myminheap->print();
    myminheap->insert(600);
    myminheap->print();

    // Get priority element from the heap
    int heapSize = myminheap->size();
    for ( int i = 0; i < heapSize; i++ )
        cout << "Get min element = " << myminheap->pop_min() << endl;

    // Cleanup
    delete myminheap;

    return 1;
}

【问题讨论】:

  • 您不得混合使用 newfree。这段代码看起来非常好。你如何使用它?确切的错误消息是什么(或者是什么让你认为,如果没有这样的消息,那就是泄漏)?
  • 总是调用虚拟析构函数。你的问题在别处。发布一个重现错误的完整示例。
  • 这并不意味着内存泄漏。贴出代码,展示你如何使用这个类。
  • 这个帖子对我来说似乎是不可能的,我也试过了,以防万一。调用虚析构函数,没有错误等
  • edit: 完整代码现已发布..

标签: c++ memory-leaks free


【解决方案1】:

如果您新建了一个 MinHeap,则不能通过在 Heap 类型上调用 free 来删除它。您的问题是您正在存储指向该对象的指针并说它是另一回事,因此删除例程不知道您正在尝试删除 MinHeap,并且只删除了 Heap 部分(大致)。

您可以直接在 myminheap 对象上调用 delete,应该可以。

更好的解决方案是根本不在堆上创建 MinHeap,在堆栈上创建并在没有任何指针的情况下使用它。如果您出于某种原因需要在堆上创建它,请改为在智能指针类中创建它,例如使用 shared_ptr 这将极大地帮助您。

【讨论】:

  • 完整的代码没有显示,但是它第一次显示new,然后是free,所以我不清楚这与崩溃的代码相同。
  • @ShafikYaghmour new 首先是 delete,因为它现在在更新的帖子中显示,new 然后是 free 没有错误弹出.. 注意:free 修改在上面的完整代码之前提到了我尝试过的
猜你喜欢
  • 2017-08-08
  • 2020-10-26
  • 2019-11-09
  • 2012-02-03
  • 1970-01-01
  • 2012-09-02
  • 2016-10-15
  • 2021-06-13
  • 1970-01-01
相关资源
最近更新 更多