1

我正在尝试为最小堆编写 C++ 代码。我想创建一个指针向量并确保它们被正确删除。

我能够创建一个指针向量,但是我从默认构造函数中得到一个无效的转换错误。为什么会这样?

此外,我正在尝试编写用户定义的析构函数以确保我没有任何内存问题。但是,我无法弄清楚为什么我会收到指针未分配的错误。

#include <vector>
#include <iostream>

struct A
{
  A(int av, int bv):a(av),b(bv){}
  int a, b;
};

struct Heap
{
   Heap() : ptr(new std::vector<A*>()) {}  //WHY AM I GETTING AN ERROR FOR THE DEFAULT CONSTRUCTOR AND NOT THE CONSTRUCTOR BELOW?
   //ERROR: invalid conversion from ‘std::vector<A*, std::allocator<A*> >*’ to ‘long unsigned int’
   //ERROR: initializing argument 1 of ‘std::vector<_Tp, _Alloc>::vector(size_t, const _Tp&, const _Alloc&) [with _Tp = A*, _Alloc = std::allocator<A*>]’

   Heap(std::vector<A*> p) : ptr(p) {  //Works fine. 
       makeHeap();
   }

  ~Heap(){   //I DON'T UNDERSTAND WHY I AM GETTING A MEMORY ERROR HERE
        std::vector<A*>::iterator it;
    for(it=ptr.begin(); it<ptr.end(); ++it)
    {  
      delete *it;
      *it=NULL;
    }
  }//ERROR:  malloc pointer being freed was not allocated  

  void makeHeap()
  {  //some code  }

  std::vector<A*> ptr;
  std::vector<int> heapLoc;
};


int main()
{
  A a0(2,5), a1(4,2);  
  std::vector<A*> aArray;  
  aArray.push_back(&a0);
  aArray.push_back(&a1);

  Heap h(aArray);

  return 0;

}
4

3 回答 3

2

ptr是指针向量,而不是指向向量的指针。所以你不能用来new在堆上构造它并存储地址。

相反,像这样构造它:

Heap() : ptr() {}

这是调用 的默认构造函数ptr,即它将创建一个空的指针向量。您还应该考虑更改名称,ptr因为它不是真正的指针。


关于你的析构函数(Dietmar 同时发布了一个答案,在他之前 Cameron 发表了评论,这解释了它(+1),但为了完整起见):你得到一个内存错误,因为你存储在你的向量中的指针参考您在堆栈上创建的对象的地址。具体来说,您在此处创建的对象:

int main()
{
  A a0(2,5), a1(4,2);  // <-- automatic storage, so they
                       //     will be deallocated automatically
  /* ... */
}

如果您希望您的Heap对象负责它自己的对象,您应该让您的构造函数在堆上创建对象,然后析构函数可以删除这些对象。一种方法是定义Heap如下的复制构造函数:

Heap(const std::vector<A*> &p) : ptr() {
  std::vector<A*>::const_iterator it(p.begin());
  for ( ; it != p.end() ; ++it)
    ptr.push_back(new A(**it));
}

您的析构函数可以按原样使用,但您可能希望使用!=而不是<在 for 循环中使用。

~Heap() {
   std::vector<A*>::iterator it;
   for(it=ptr.begin(); it != ptr.end(); ++it)
   {  
     delete *it;
     *it=NULL;
   }

最后,我不确定您是否真的需要指针向量(而不是对象向量),但如果您认为需要,请考虑使用智能指针(例如 C++11 提供std::unique_ptr,因此您可以定义 astd::vector<std::unique_ptr<A>>来解决许多与分配相关的问题)。

于 2012-11-25T01:01:55.797 回答
2

为什么默认构造函数而不是下面的构造函数出现错误?

ptr(new std::vector<A*>())

这是因为 operatornew返回一个指向 的指针std::vector而不是 avector本身。由于您将 a 声明vector为对象,因此您应该简单地删除整个ptr(...)部分:ptr编译器将正确初始化 a 。

一种更现代的方法是unique_ptr<T>代替“原始”指针。这将确保在销毁时自动正确销毁vector<unique_ptr<T>>

于 2012-11-25T01:03:26.673 回答
1

由于人们没有指出:当您Heap使用指向堆栈的指针销毁时,即未在空闲存储上分配的对象(我正要说“堆”,但这可能会导致不必要的混乱......)你'也会得到有趣的行为。这整个方法从一开始就注定要失败:除非您真的知道自己在做什么,否则不要使用原始指针容器!(即使那样你最好不要使用原始指针容器)

于 2012-11-25T01:06:22.493 回答