清理双重链表(c++)中的内存泄漏

Cleaning up memory leaks in Doubly Linked List(C++)

本文关键字:内存 泄漏 c++ 链表      更新时间:2023-10-16

我正试图修复这个双链表中的一些内存泄漏。我的析构函数似乎出错了。我需要删除析构函数之外的任何东西吗?有了这个,我试图保持所有的删除语句在它。任何帮助都是感激的。下面是valgrind给我的:

==29075== Invalid read of size 8
==29075==    at 0x400BC0: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:32)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075==  Address 0x5a04050 is 16 bytes inside a block of size 24 free'd
==29075==    at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400BBB: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:31)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075== 
==29075== Invalid read of size 8
==29075==    at 0x400BEC: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:36)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075==  Address 0x5a040a8 is 8 bytes inside a block of size 24 free'd
==29075==    at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400BE7: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:35)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075== 
==29075== Invalid read of size 8
==29075==    at 0x400BF8: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:34)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075==  Address 0x5a04048 is 8 bytes inside a block of size 24 free'd
==29075==    at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400BBB: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:31)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075== 
==29075== Invalid free() / delete / delete[] / realloc()
==29075==    at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400BE7: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:35)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075==  Address 0x5a04040 is 0 bytes inside a block of size 24 free'd
==29075==    at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400BBB: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:31)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075== 
==29075== 
==29075== HEAP SUMMARY:
==29075==     in use at exit: 96 bytes in 4 blocks
==29075==   total heap usage: 7 allocs, 4 frees, 168 bytes allocated
==29075== 
==29075== 24 bytes in 1 blocks are definitely lost in loss record 1 of 4
==29075==    at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400D00: DblLinkedList<int>::insertFirst(int) (DblLinkedList.cpp:75)
==29075==    by 0x4009FB: main (DblLinkedList.cpp:192)
==29075== 
==29075== 24 bytes in 1 blocks are definitely lost in loss record 2 of 4
==29075==    at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400D54: DblLinkedList<int>::insertLast(int) (DblLinkedList.cpp:85)
==29075==    by 0x400A28: main (DblLinkedList.cpp:196)
==29075== 
==29075== 24 bytes in 1 blocks are definitely lost in loss record 3 of 4
==29075==    at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400B84: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:26)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075== 
==29075== 24 bytes in 1 blocks are definitely lost in loss record 4 of 4
==29075==    at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29075==    by 0x400B92: DblLinkedList<int>::~DblLinkedList() (DblLinkedList.cpp:27)
==29075==    by 0x400ABF: main (DblLinkedList.cpp:215)
==29075== 
==29075== LEAK SUMMARY:
==29075==    definitely lost: 96 bytes in 4 blocks
==29075==    indirectly lost: 0 bytes in 0 blocks
==29075==      possibly lost: 0 bytes in 0 blocks
==29075==    still reachable: 0 bytes in 0 blocks
==29075==         suppressed: 0 bytes in 0 blocks
==29075== 
==29075== For counts of detected and suppressed errors, rerun with: -v
==29075== ERROR SUMMARY: 10 errors from 8 contexts (suppressed: 2 from 2)

代码如下:

#include <iostream>
using namespace std;
template <class T>
class DblLinkedList
{
private:
    struct node
    {
        T data;
        node* prev;
        node* next;
    };
    node* head;
    node* tail;
    int count;
public:
    DblLinkedList() {
        head = nullptr;
        tail = nullptr;
            count = 0;
    }

    /** This seems to be the 
    problem right here **/
    ~DblLinkedList(){
        node* p = new node;
        node* q = new node;
        p = head;
        q = tail;
        while(p->next != nullptr){
            delete p;
            p = p->next;
        }
        while(q->prev != nullptr){
            delete q;
            q = q->prev;
        }
    }

    void createList(T[], int);
    void insertFirst(T);
    void insertLast(T);
    void insertAfter(T,T);

};

//creating DblLinkedList
template<class T>
void DblLinkedList<T>::createList(T x[], int n)
{
    node* q;
    node* p = new node; //first node
    head = p;
    p->data = x[0];
    p->next = nullptr;
    p->prev = nullptr;
    for(int tom = 1; tom < n; tom++){
        q = p;
        p = p->next = new node;
        p->data = x[tom];
        p->next = nullptr;
        p->prev = q;
        count++;
    }
    tail = p;
}

//insert new node at start of DblLinkedList
template <class T>
void DblLinkedList<T>::insertFirst(T item){
    node *p = new node;
    p->data = item;
    p->prev = nullptr;
    head->prev = p;
    count++;
}
//insert node at end of DblLinkedlist
template<class T>
void DblLinkedList<T>::insertLast(T item){
    node *p = new node;
    p->data = item;
    p->prev = nullptr;
    head->prev = p;
    count++;
}

//insert new node after an item in DbLinkedList
template <class T>
void DblLinkedList<T>::insertAfter(T item, T k)
{
    node *q = head;
    while (q != nullptr){
        if(q->data == k){ break; }
        q = q->next;
    }
    if(q == nullptr)
    {
        cout << key << "not found" << endl;
        return;
    }
    node *p = new node;
    p->data = item;
    p->next = q->next;
    p->prev = q;
    q->next = p;
    count++;
}
int main()
{
    int x[2] = {33,44};
    DblLinkedList<int> dList;
    dList.createList(x, 2);
    cout << "Insert First 22" << endl;
    dList.insertFirst(22);
    cout << "Insert Last 55" << endl;
    dList.insertLast(55);
    cout << "Insert 66 After 33" << endl;
    dList.insertAfter(66,33);
    return 0;
}

修复内存泄漏最简单的方法是使用std::list:

#include <list>
#include <iostream>
#include <algorithm>
int main()
{
   int const x[2] = {33,44};
   std::list<int> dList(std::begin(x), std::end(x));
   std::cout << "Insert First 22" << std::endl;
   dList.push_front(22);
   std::cout << "Insert Last 55" << std::endl;
   dList.push_back(55);
   std::cout << "Insert 66 After 33" << std::endl;
   std::list<int>::iterator it {
      std::find(std::begin(dList), std::end(dList), 33) };
   if( it!=dList.end() ) {
      dList.insert(it, 66);
   }
   for( auto const li : dList ) {
      std::cout << "o " << li << std::endl;
   }
   return 0;
}
输出:

$ valgrind ./a.out 
==7126== Memcheck, a memory error detector
==7126== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==7126== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==7126== Command: ./a.out
==7126== 
Insert First 22
Insert Last 55
Insert 66 After 33
o 22
o 66
o 33
o 44
o 55
==7126== 
==7126== HEAP SUMMARY:
==7126==     in use at exit: 0 bytes in 0 blocks
==7126==   total heap usage: 5 allocs, 5 frees, 120 bytes allocated
==7126== 
==7126== All heap blocks were freed -- no leaks are possible
==7126== 
==7126== For counts of detected and suppressed errors, rerun with: -v
==7126== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)

删除双链表与删除单链表相同。您不必遍历尾部来清理列表。

while(p->next != nullptr)
{
    delete p; // p is deleted here 
    p = p->next; // never perform a operation on pointer which is deleted
}

应该是

node* p = head;
while( p != 0 ) {
    node* next = p->next;
    delete p;
    p = next;
}
head = 0;

使用容器作为指针以避免内存管理的开销。您可以使用unique_ptr容器来管理指针。你可以在下面找到更多的细节

http://en.wikipedia.org/wiki/Smart_pointer

http://www.cplusplus.com/reference/memory/unique_ptr/

http://www.cplusplus.com/reference/memory/unique_ptr/unique_ptr/