析构函数中的释放导致内存泄漏

时间:2009-08-26 09:06:05

标签: c++

我必须使用C ++中的数组编写一个堆栈类模板用于我的任务。

Here是我的代码:

#include <iostream>

template <typename Type>
class Stack {
private:
  int top;
  Type items[];
public:
  Stack()  { top = -1; };
  ~Stack() { delete[] items; };
  void push(Type);
  bool isEmpty() const;
  Type pop();
  Type peek() const;
};

int main (int argc, char *argv[]) {
  Stack<double> st;
  return 0;
}

template<typename Type>
void Stack<Type>::push(Type item) {
  top++;
  if(top == sizeof(items) / sizeof(Type)) {
    Type buff[] = new Type[top];
    std::copy(items,items+top,buff);
    delete[] items;
    items = new Type[2*top];
    std::copy(buff,buff+top,items);
    delete[] buff;
  }
  items[top] = item;
}

template<typename Type>
bool Stack<Type>::isEmpty() const {
  return top == -1 ? true : false;
}

template<typename Type>
Type Stack<Type>::pop() {
  //TODO
  return items[top--];
}

template<typename Type>
Type Stack<Type>::peek() const{
  //TODO
  return items[top-1];
}

使用“g++ -Wall”编译好了,但是当我运行程序时,我收到了这个错误:

  

*检测到glibc * ./lab3: munmap_chunk(): invalid pointer: 0x00007fff41a3cdf8

在尝试使用GDB后,我发现错误来自以下行:

'free[] items' in the destructor.

我不明白为什么释放数组会导致内存泄漏?有线索吗?

5 个答案:

答案 0 :(得分:6)

您应该只delete[]使用new[]明确分配的内容。您的items成员不是动态分配的数组,因此您不能像以前一样释放它。

另一方面,你有

Type items[];

实际上并没有在堆栈的对象实例中分配任何空间。

答案 1 :(得分:4)

我认为这不是内存泄漏!发生崩溃是因为您删除了非堆对象。

答案 2 :(得分:3)

您没有新项目,因此您无法在析构函数中删除它。假设你需要'Stack'是一个动态大小的类,那么items数组必须是动态分配的,在这种情况下,items的声明应该是

Type *items;    (as hacker mentions above)

并且构造函数应调用'items = new Type [ARRAY_SIZE]'来分配内存,或者至少最初将'items'指针指向NULL。

根据评论进行编辑 -

要完成并保护此类的内存​​分配职责,还应包括复制构造函数和赋值运算符,该运算符分配新内存并将存储在项中的值复制到新对象。这避免了指针简单地被编译器生成的复制构造函数或赋值运算符复制,这将导致多个对象指向相同的动态分配的内存。在销毁这些对象中的第一个时,将删除该存储器。通过共享指针的其他对象进一步使用现在删除的内存可能会导致崩溃。

我没有在这里添加代码,而是引用了Martin对this question的回答中的代码。

答案 3 :(得分:2)

items 是指向Type的指针。必须初始化此指针 在使用之前(它是wild pointer)。那 这就是你的程序崩溃的原因。它发生在 析构函数是巧合。它也可以 发生得早。例如。在push()内存中被覆盖 恰好指向的位置。

您需要为许多元素分配内存。见下文。

你已经拥有了动态增长的逻辑 阵列到位。但是C ++中的数组并不知道它的大小 (它只是某种类型的指针)。你需要跟踪 目前的容量/大小。因此,而不是

sizeof(items)

定义一个新成员以保持当前容量。

E.g:

int capacity;

并在构造函数中:

capacity = 100;
items = new Type[capacity];

最后一行分配了许多元素,是解决问题的主要方法。

在push()中:

if (top == capacity / sizeof(Type)) {

重新分配的逻辑需要改变。 E.g:

capacity *= 2;
items = new Type[capacity];

而不是
    items = new Type [2 * top];

我刚刚在这里草拟了一个解决方案。 Yon可以填写详细信息。


注意:您的程序中只有一个Stack实例; main()的主体是:

Stack<double> st;

如果您将一个Stack实例分配给另一个实例,例如

{
   Stack<double> st;
   Stack<double> st2 = st; //Copy constructor will be invoked for st2. If not defined the compiler generated copy constructor will do a copy of the pointer value.
   Stack<double> st3;
   st3 = st; //Assignment operator will be invoked for st3. If not defined the compiler generated assignment operator will do a copy of the pointer value.
}

然后是复制构造函数(为st2工作)和 Stack的赋值运算符(为st3工作)必须是 正确定义(制作被引用成员的副本 的)。否则在析构函数中删除两次或三次 未定义的行为(例如崩溃)将是结果 st,st2和st3超出了近距离的范围。

答案 4 :(得分:1)

我看到的第一件事是你可能意味着Type *items,而不是Type items[]

然后你不想(不能)对动态分配的数据使用sizeof