内存泄漏;当删除异常时引发

时间:2013-05-25 13:06:53

标签: c++ memory-leaks valgrind

我正在编写一个可调整大小的数组类(std :: vector),作为练习,使用手动指针(因为我想在开始使用智能指针之前知道它们是如何工作的)。但是,Valgrind在checkMax()函数中报告内存泄漏。

template <typename T>
class Array{
 public:
 Array() : len(0),maxLen(1){
    array=new T[maxLen];
    // ........ 
}
Array(unsigned length, T&content=0) : len(length),maxLen(length*2){
    array=new T[maxLen];
    //..............
}
~Array(){
    //delete[] array;
}
//..............
void push_back(const T& content){
    checkMax();
// do stuff...
}
private:
T* array;
unsigned int len;
unsigned int maxLen;
..
void checkMax(){
    if(len==maxLen){
    //allocate more memory for the array
        maxLen*=2;
        T*temp=new T[maxLen]; // ------------- MEMORY LEAK HERE -------------
        for(unsigned int i=0; i<len; i++){
            temp[i]=array[i];
        }
        delete [] array;
        array=temp;
    }
}
};

我这里只发布了与内存相关的代码。

我不明白为什么Valgrind报告指定行的内存泄漏。我将旧的数组内容复制到放大的数组后删除旧数组,后两行。

另外,如果我在析构函数中取消注释delete []函数,我会得到异常double free or corruption并且Valgrind报告无效删除(暗示重新删除),所以我完全陷入困境。 有什么想法吗?

修改       感谢您的早期回复!阅读完评论之后,我发现问题不在于我的类,而是在另一个函数中,我使用Array类作为参数调用 。如果我删除了对该函数的调用,并在类中添加了delete调用,则不会发生内存泄漏。这是我的功能:

template <typename T>
void printContents(Array<T> ar){
for(unsigned int i=0; i<ar.size(); i++){
    cout<<"Content at i in array = " << ar.at(i) << endl;
}
}

在阅读了三条规则(感谢克里斯)和Grizzly发布的答案之后,我现在已经理解了删除[]无效的原因。因为我没有重载复制构造函数,所以发生了浅层复制,由于这个问题,我的数组指针已经分配到ar中的指针,而当ar超出范围时,调用了delete [],从而在主函数无效中进行删除。因此,我得到了例外。如果我删除了删除,那么数组显然会保持分配并导致内存泄漏。

感谢您的帮助,我已将Grizzly的回答投票为正确。

1 个答案:

答案 0 :(得分:2)

通过不在析构函数中调用delete[]来泄漏内存。这意味着在对象(对象中的“最终”数组)上最后一次调用checkMax时分配的数组不会被调用。因此,要解决这个问题,您应该取消注释析构函数中的delete[]

正如你所提到的,这会给你一个双重免费的问题。这是基于违反三规则(在C ++ 03中它是三个规则,在C ++ 11中情况不是那么明确,但对于这种情况,三的规则足以解决你的问题)。三个规则基本上表明,当您定义自定义析构函数,复制构造函数或赋值运算符时,您需要定义所有这些。在这种情况下,您可能会在某处复制Array。这意味着两个实例将包含相同的指针并尝试在析构函数中删除它。在同一个指针上调用两次删除是一个错误。要解决该问题,您需要定义自定义复制构造函数和赋值操作,在该操作中,您可以执行数组的深层复制(分配新内存并复制内容)。

除了所有的事情外,我个人建议从智能指针开始,然后才能更好地掌握C ++,开始尝试手动内存管理。