内存泄漏,节点列表C ++

时间:2015-03-05 14:01:13

标签: c++ pointers memory-leaks

我有一个旧考试的代码,我想从错误中解决这个问题。每次我调用insertlast / insertfirst时,我都会为我的列表分配新的内存,这些内存似乎无法释放。我用valgrind运行它并且每次调用insertfirst / insertlast时都会获得新的泄漏。 Valgrind也抱怨我的循环,我试图释放内存。我得到这样的东西:

Invalid free() / delete / delete[] / realloc()
==4548==    at 0x4C2C2BC: operator delete(void*)(in/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4548==    by 0x4007D6: main (code6.cpp:67)
==4548==  Address 0xffefffea0 is on thread 1's stack

以下是代码:

#include <iostream>
using namespace std;

template <class T>
struct Node {
    Node() : data(T()), next(nullptr) {}
    Node(T d, Node * p) : data(d), next(p) {}
    T data;
    Node<T> * next;
};

template <class T>
void insertlast (Node<T> * p, T data) { 
    if (p == nullptr) {
        p = new Node<T>(data, nullptr);
    } else {
        while (p -> next != nullptr) {
            p = p -> next;
        }
        p -> next = new Node<T>(data, nullptr);
    }
}

template <class T>
void insertfirst (Node<T> * & p, const T & data) {
    Node<T> * tmp = new Node<T>(data, p);
    p = tmp;
}

template <class T>
void printNode(Node<T> *& node) {
    cout << node->data << " -> ";
    while (node->next != nullptr) {
        node = node->next;
        cout << node->data << " -> ";
    }
    cout << endl;
}


template <class T>
void printNode2(Node<T> & node) {
    cout << node.data << " -> ";
    while (node.next != nullptr) {
        node = *node.next;
        cout << node.data << " -> ";
    }
    cout << endl;
}


int main() {
    Node<int> node;
    Node<int> * temp = &node;
    Node<int> * ref = &node;

    insertlast(ref, 5);
    insertfirst(ref, 3);
    insertlast(ref, 6);
    insertfirst(ref, 2);

    //printNode(ref);
    //printNode2(node);

    while(ref->next != nullptr){
        temp = ref->next;
        delete ref;
        ref = temp;
    }
    return 0;
}

如果你能帮助我找出代码有什么问题,那将会很酷。我的猜测是它在insertfirst中的指针引用是可疑的,但我无法弄明白。 提前谢谢!

3 个答案:

答案 0 :(得分:2)

第一次调用insertfirst时,您将创建一个新节点,其next指针是来自node的静态分配的main对象,然后当您循环时要删除其中的节点的列表,您将尝试删除此node对象。

如果你想在列表的头部有一个sentinel对象,你应该做的是使它的next指针指向新节点,新节点的下一个指针应该设置为{{ 1}}。像

这样的东西
p->next

最后提示如何调试这些东西:在纸上画出每次操作后,将它画在纸上,这样的问题很容易被发现。

答案 1 :(得分:0)

insertlast函数中,如果参数pNULL,那么您的代码将泄漏Node的实例。您创建新实例并将其地址分配给p,但是一旦离开该函数,p就会超出范围,您不再有指向新创建的实例的指针。

我想你想在p函数中传递对insertfirst的引用,但忘记将&字符放在那里。

答案 2 :(得分:0)

这两个函数的接口不一致

template <class T>
void insertlast (Node<T> * p, T data) { 
    if (p == nullptr) {
        p = new Node<T>(data, nullptr);
    } else {
        while (p -> next != nullptr) {
            p = p -> next;
        }
        p -> next = new Node<T>(data, nullptr);
    }
}

template <class T>
void insertfirst (Node<T> * & p, const T & data) {
    Node<T> * tmp = new Node<T>(data, p);
    p = tmp;
}

在第一个函数中,参数声明为Node<T> * p, T data,而在第二个函数中,参数声明为Node<T> * & p, const T & data

在第一个函数中,您还应通过引用传递第一个参数。否则p是函数的局部变量,它的变化不会影响原始参数。

可以通过以下方式定义

template <class T>
void insertlast ( Node<T> * &p, const T &data ) 
{ 
    if ( p == nullptr ) 
    {
        p = new Node<T>(data, nullptr);
    } 
    else 
    {
        Node<T> *tmp = p;
        while ( tmp->next != nullptr ) 
        {
            tmp = tmp->next;
        }

        tmp->next = new Node<T>( data, nullptr );
    }
}

此外,您必须将main中的第一个节点初始化为nullptr

Node<int> *node = nullptr;

在堆栈中定义列表的第一个节点是个坏主意。这只是一个无效的设计。