Как я могу удалить связанный список без утечки памяти? - PullRequest
0 голосов
/ 20 мая 2019

Я пытаюсь создать телефонную книгу и храню свои данные в связанном списке. Однако, когда я пытаюсь удалить его, я либо получаю утечку памяти, либо какое-то уродливое состояние выхода с некоторым значением из памяти. Я предполагаю, что это состояние выхода сигнализирует о некоторых проблемах при удалении моего списка, потому что программа не перейдет к следующей строке.

Я пытался связываться с деструкторами взад и вперед, но, кажется, я не могу решить это самостоятельно.

У меня есть три важных класса. Один для телефонной книги, один для контакта и один для члена данных контакта. Класс Data является абстрактным и имеет несколько производных классов. Также у меня есть структура связанного списка, которую я использую для хранения контактов в телефонной книге и для хранения данных в контакте.

Структура связанного списка:

#include "Data.h"
class Contact; //to avoid an "undefined reference" error

struct ListMem{
    ListMem* next=NULL;
    Contact* cont=NULL;
    Data* dat=NULL;
}; //this class can't have a destructor that calls "delete cont",
//because of the order I declared my classes in

Класс телефонной книги:

#include "Contact.h"
#include "ListMem.h"

class Phonebook{
    size_t cont_num; //how many contacts are already stored
    ListMem* cont; //pointer to the first member of the linked list
public:
    Phonebook(const char* filename){ //reads the Phonebook from file
        std::ifstream is;
        is.open(filename);
        size_t pb_size;
        string line;
        ListMem* tmp;
        is>>pb_size; getline(is, line);
        cont_num=0;

        for(size_t i=0; i<pb_size; i++){
            getline(is, line);
            if(i==0){
                Contact* tmp_ct=new Contact(line);
                cont=add_cont(tmp_ct);
                tmp=cont;
            }
            else {
                Contact* tmp_ct=new Contact(line);
                tmp->next=add_cont(tmp_ct);
                tmp=tmp->next;
            }
        }
    }

    ListMem* add_cont(Contact* new_ct){ //adds a new contact
        ListMem* tmp=new ListMem;
        tmp->cont=new Contact(new_ct);
        cont_num++;
        return tmp;
    }

    ~Phonebook(){
        ListMem* tmp=cont;
        while(tmp!=NULL){
            ListMem* del=tmp;
            tmp=tmp->next;
            delete del->dat;
            delete del->cont;
            delete del;
        }
    }
};

Класс контакта:

#include "Name.h"
#include "ListMem.h"

class Contact{
    size_t data_num; //number of data stored
    ListMem* data; //pointer to the first data member
public:
    Contact(string line){ //converts a "line" into a Contact
        ListMem* tmp;
        int dat_count=std::count(line.begin(), line.end(), ':');
        data_num=dat_count;
        string dat, tmp_dat, tmp_type;
        int pos_1=0, pos_2=line.find(';');

        for(int i=0;i<dat_count;i++){
            dat=line.substr(pos_1, pos_2-pos_1);
            tmp_type=dat.at(0);
            tmp_dat=dat.substr(2, dat.size()-2);
            pos_1+=dat.size()+1;
            pos_2=line.find(';', pos_1);
            if(i==0){
                data=add_data(tmp_type, tmp_dat);
                tmp=data;
            }
            else {
                tmp->next=add_data(tmp_type, tmp_dat);
                tmp=tmp->next;
            }
        }
    }

    ListMem* add_data(string type, string data){ //adds a new data member
            ListMem* tmp=new ListMem;
            if(type=="1") tmp->dat=new Name(data);
            //I have more, but it's irrelevant.
            data_num++;
            return tmp;
    }

    ~Contact(){
        ListMem* tmp=data;
        while(tmp!=NULL){
            ListMem* del=tmp;
            tmp=tmp->next;
            delete del->dat;
            delete del->cont;
            delete del;
        }
    }
};

Класс данных:

class Data{
    string type;
public:
    Data(){}
    void set_type(string t) {type=t;}
    virtual ~Data(){}
};

Один из производных классов, остальные выглядят в основном одинаково:

#include "Data.h"

class Name: public Data{
    string name;
public:
    Name(string n): name(n){ set_type("1");}
    ~Name(){}
};

И, конечно, главное:

#include "Phonebook.h"

int main(){
    Phonebook* Test=new Phonebook("test.txt");
    delete Test;

    return 0;
}

В файле 'test.txt' у меня есть тестовая телефонная книга:

3
1:test_name_1;
1:test_name_2;
1:test_name_3;

Поэтому, когда я запускаю этот код, у меня возникает утечка памяти, и я не знаю почему. Я заставил деструктор бегать по связанному списку и освобождать динамическую память, или, по крайней мере, так я думал.

Я знаю, что я не освобождаю контакты так, как должен, потому что я использовал инструмент проверки утечки памяти, и шаблон повторяет те же самые контакты, что и я.

Я использовал файлы .cpp, но интегрировал соответствующие части здесь, чтобы сэкономить место. Также я не включил сюда другие, кроме моей системы проектов.

Я сильно подозреваю, что проблема связана с деструкторами: ~ Phonebook (), ~ Contact () или обоими. Я разместил здесь другие части, потому что мне сказали опубликовать версию, которую любой может воспроизвести без особых проблем. Я чувствую, что должна быть глупая ошибка и простое решение, но я не знаю, что.

Можете ли вы, ребята, помочь мне немного?

1 Ответ

0 голосов
/ 20 мая 2019

Конструктор телефонной книги анализирует файл, создает объект Contact с помощью оператора new и передает его в add_cont (). Функция-член add_cont () создает копию объекта Contact, переданного в качестве параметра снова, используя оператор new, но никогда не удаляет origin. С моей точки зрения, в add_cont () 'new_ct' просто можно присвоить 'tmp-> cont'.

Кстати, лучшим подходом будет использование доступных контейнерных классов, таких как std :: list, std :: vector и т. Д., И избегание необработанных указателей.

...