c ++链表析构函数valgrind内存泄漏

时间:2015-10-30 19:29:36

标签: c++

嗨,我有一个链表实现,我在valgrind中得到了内存泄漏错误...最初有4个但是在修复它之后,我仍然得到两个。

头:

class LL1{
public:
    LL1(); //default construtor
    LL1(const LL1& lst); //copy constructor
        ~LL1();//destructor

    void add(int data);


    void insertAt(int pos, int data);

    bool remove(int data );

    void removeAll();
    // Empties the list.

    void printList();
    // Prints the contents of the list to the screen, in order

private:

    // List node
    struct Node {
        int data; //list data
        Node *next; //pointer to next item in the list
    };

    Node *head; //Pointer to the first node in the list
    int size; //Records the number of nodes in the list
};

implemen:

// Implementation of the LinkedList class
// Version 1: Full of memory leaks.

#include "LL1.h"
#include <string>
#include <iostream>

using namespace std; 

// Default constructor
LL1::LL1(){
    head = NULL;
    size = 0;
}

LL1::LL1(const LL1& lst){
        head = lst.head; //shallow copy - this is an error!
        size = lst.size;
}

// Destructor.
LL1::~LL1(){
    Node *ptr=head;  
    Node *temp;
    while (ptr != NULL)
    {
        temp = ptr->next;
        delete ptr;
        ptr = temp;
    }
}

/**************************************************************************/
// Operations

void LL1::add(int x){
    Node *p = new Node; //temporary node
    // Assign appropriate values to the new node
    p -> data = x;
    p -> next = head;
    // Make the head point to the new node
    head = p;   
    size++;
}

void LL1::insertAt(int pos, int x){
        Node *p;
        Node *newNode;

        // Check that pos is a valid index
        if (pos <= size){
                newNode = new Node; //new node
                newNode->data = x;

                if (pos == 0){
                        newNode->next = head;
                        head = newNode;
                }// if(pos == 0)
                else{
                        p = head;
                        // Move to position BEFORE insertion point
                        for(int i = 0; i < pos-1; i++){

                                if(p == NULL){
                                        return;
                                }
                                p = p->next;
                        }//for
                        // Insert node
                        newNode->next = p->next;
                        p->next = newNode;
                }//else (pos != 0)
                size++;
        }//else (pos >= size) do nothing
}

bool LL1::remove(int x){
    Node *p = head;
    // Check to see if the list exists
    if (head == NULL){
        return false;
    }
    else if (head->data == x){
        head = head->next;
        size--;
        return true;
    }
    // Otherwise iterate through list
    else{
        while(p->next != NULL){
            // Check next node for target
            if(p->next->data == x){
                p->next = p->next->next;
                return true;
                                size-- ;
            }
            p = p->next;
        }
    }
    return false;
}

// Empties the list.
void LL1::removeAll(){
    head = NULL;
    size = 0;
}

void LL1::printList(){
    Node *p = head;
    cout << "["; //Nice format!
    // Traverse the list
    while (p != NULL){
        cout << p -> data; // Print data
        p = p -> next; // Go to next node
        if (p != NULL){
            cout << ","; // Print a comma unless at the end of the list
        }
    }
    cout << "]"; // Don't print a newline - it might not be wanted
}

测试/主文件:

#include "LL1.h"

#include <iostream>
using namespace std;

void listTest();

int main() {
    cout << "!!!Hello!!!" << endl;
        listTest();
    cout << "!!!Goodbye!!!" << endl; 
    return 0;
}

void listTest(){

        cout << "A little exercise with memory leaks in the LL1 linked list class." << endl << endl ;

    cout << "List1 and List1A are empty LL1 instances in heap memory." << endl;
    LL1 * ls1;
    LL1 * ls1A;
        ls1 = new LL1();
        ls1A = new LL1();
    cout << "Add 1,2,3,4 to List1 and List1A." << endl;
    ls1->add(1);
    ls1->add(2);
    ls1->add(3);
    ls1->add(4);
    ls1A->add(1);
    ls1A->add(2);
    ls1A->add(3);
    ls1A->add(4);
    cout << "List1 is:"; ls1->printList(); cout << endl << endl; 
    cout << "List1A is:"; ls1A->printList(); cout << endl << endl; 

    cout << "Remove some items from List1" << endl;
    ls1->remove(2);
    ls1->remove(4);
        cout << "List1 is:" ; ls1->printList() ; cout << endl ;  

        cout << "Now, empty List1 with removeAll" << endl ;
        ls1->removeAll();
        cout << "List1 is:" ; ls1->printList() ; cout << endl ;  

        cout << endl ;

        cout << "That's all!" << endl;
    delete ls1;
    delete ls1A;
}

valgrind错误:

==25924== Memcheck, a memory error detector
==25924== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25924== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==25924== Command: ./test
==25924== 
!!!Hello!!!
A little exercise with memory leaks in the LL1 linked list class.

List1 and List1A are empty LL1 instances in heap memory.
Add 1,2,3,4 to List1 and List1A.
List1 is:[4,3,2,1]

List1A is:[4,3,2,1]

Remove some items from List1
List1 is:[3,1]
Now, empty List1 with removeAll
List1 is:[]

That's all!
!!!Goodbye!!!
==25924== 
==25924== HEAP SUMMARY:
==25924==     in use at exit: 64 bytes in 4 blocks
==25924==   total heap usage: 10 allocs, 6 frees, 160 bytes allocated
==25924== 
==25924== 32 (16 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 4
==25924==    at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25924==    by 0x400E4E: LL1::add(int) (in /home/mani/Desktop/lab3/test)
==25924==    by 0x400B34: listTest() (in /home/mani/Desktop/lab3/test)
==25924==    by 0x400A51: main (in /home/mani/Desktop/lab3/test)
==25924== 
==25924== 32 (16 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==25924==    at 0x4C2B0E0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25924==    by 0x400E4E: LL1::add(int) (in /home/mani/Desktop/lab3/test)
==25924==    by 0x400B56: listTest() (in /home/mani/Desktop/lab3/test)
==25924==    by 0x400A51: main (in /home/mani/Desktop/lab3/test)
==25924== 
==25924== LEAK SUMMARY:
==25924==    definitely lost: 32 bytes in 2 blocks
==25924==    indirectly lost: 32 bytes in 2 blocks
==25924==      possibly lost: 0 bytes in 0 blocks
==25924==    still reachable: 0 bytes in 0 blocks
==25924==         suppressed: 0 bytes in 0 blocks
==25924== 
==25924== For counts of detected and suppressed errors, rerun with: -v
==25924== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

1 个答案:

答案 0 :(得分:0)

// Empties the list.
void LL1::removeAll(){
    head = NULL;
    size = 0;
}

嗯,它将它遗忘,但不是那么干净。

 void LL1::removeAll(){
     //the LL1 dtor code
     Node *ptr=head;  
     Node *temp;
     while (ptr != NULL) {
         temp = ptr->next;
         delete ptr;
         ptr = temp;
        // and
         --size; 
     } 
}

会干净地清空清单,并可能让valgrind更快乐。

最好将其从dtor上移开,然后从那里拨打电话LL1::removeAll()

#include <string>
#include <iostream>
using namespace std;


class LL1 {
public:
    LL1(); //default construtor
    LL1(const LL1& lst); //copy constructor
    ~LL1();//destructor

    void add(int data);


    void insertAt(int pos, int data);

    bool remove(int data );

    void removeAll();
    // Empties the list.

    void printList();
    // Prints the contents of the list to the screen, in order

private:

    // List node
    struct Node {
        int data; //list data
        Node *next; //pointer to next item in the list
    };

    Node *head; //Pointer to the first node in the list
    int size; //Records the number of nodes in the list
};

// Implementation of the LinkedList class
// Version 1: Full of memory leaks.


using namespace std;

// Default constructor
LL1::LL1() {
    head = NULL;
    size = 0;
}

LL1::LL1(const LL1& lst) {
    head = lst.head; //shallow copy - this is an error!
    size = lst.size;
}

// Destructor.
LL1::~LL1() {
    removeAll();
}

/**************************************************************************/
// Operations

void LL1::add(int x) {
    Node *p = new Node; //temporary node
    // Assign appropriate values to the new node
    p -> data = x;
    p -> next = head;
    // Make the head point to the new node
    head = p;
    size++;
}

void LL1::insertAt(int pos, int x) {
    Node *p;
    Node *newNode;

    // Check that pos is a valid index
    if (pos <= size) {
        newNode = new Node; //new node
        newNode->data = x;

        if (pos == 0) {
            newNode->next = head;
            head = newNode;
        }// if(pos == 0)
        else {
            p = head;
            // Move to position BEFORE insertion point
            for(int i = 0; i < pos-1; i++) {

                if(p == NULL) {
                    return;
                }
                p = p->next;
            }//for
            // Insert node
            newNode->next = p->next;
            p->next = newNode;
        }//else (pos != 0)
        size++;
    }//else (pos >= size) do nothing
}

bool LL1::remove(int x) {
    Node *p = head;
    // Check to see if the list exists
    if (head == NULL) {
        return false;
    }
    else if (head->data == x) {
        //Node* p = head;
        head = head->next;
        delete p;
        --size;
        return true;
    }
    // Otherwise iterate through list
    else {
        while(p->next != NULL) {
            // Check next node for target
            if(p->next->data == x) {
                p->next = p->next->next;
                size-- ;
                return true;
            }
            p = p->next;
        }
    }
    return false;
}

// Empties the list.
void LL1::removeAll() {
    Node *temp;
    while (head != NULL)  {
        temp = head->next;
        delete head;
        head = temp;
        --size;
    }
}

void LL1::printList() {
    Node *p = head;
    cout << "["; //Nice format!
    // Traverse the list
    while (p != NULL) {
        cout << p -> data; // Print data
        p = p -> next; // Go to next node
        if (p != NULL) {
            cout << ","; // Print a comma unless at the end of the list
        }
    }
    cout << "]"; // Don't print a newline - it might not be wanted
}



void listTest();

int main() {
    cout << "!!!Hello!!!" << endl;
    listTest();
    cout << "!!!Goodbye!!!" << endl;
    return 0;
}

void listTest() {

    cout << "A little exercise with memory leaks in the LL1 linked list class." << endl << endl ;

    cout << "List1 and List1A are empty LL1 instances in heap memory." << endl;
    LL1 * ls1;
    LL1 * ls1A;
    ls1 = new LL1();
    ls1A = new LL1();
    cout << "Add 1,2,3,4 to List1 and List1A." << endl;
    ls1->add(1);
    ls1->add(2);
    ls1->add(3);
    ls1->add(4);
    ls1A->add(1);
    ls1A->add(2);
    ls1A->add(3);
    ls1A->add(4);
    cout << "List1 is:";
    ls1->printList();
    cout << endl << endl;
    cout << "List1A is:";
    ls1A->printList();
    cout << endl << endl;

    cout << "Remove some items from List1" << endl;
    ls1->remove(2);
    ls1->remove(4);
    {
        cout << "List1 is:" ;
        ls1->printList() ;
        cout << endl ;

        cout << "Now, empty List1 with removeAll" << endl ;
        ls1->removeAll();
        cout << "List1 is:" ;
        ls1->printList() ;
        cout << endl ;

        cout << endl ;
        cout << "That's all!" << endl;
    }
    delete ls1;
    delete ls1A;
}

live version at coliru

使用g ++编译(Debian 4.9.2-10)4.9.2在linux 3.16.0-4-amd64上

g ++ -Wall -pedantic -g list2.cpp

在valgrind-3.10.0下运行

valgrind -v ./aout

给出

[...]
==18230== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==18230== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)