Утечки памяти в программе для реализации связанного списка в C ++ - PullRequest
0 голосов
/ 15 марта 2020

В настоящее время я пишу программу для mimi c функций связанного списка. Я думаю, что код сбой из-за утечек памяти, но я не могу понять, где они могут быть. Я пытался удалять после каждого нового, но когда я удаляю это, функции не работают правильно. Я также думаю, что моя функция push_back () может работать неправильно, потому что мой вывод не совпадает с выводом std :: list. Любая помощь будет принята с благодарностью. Спасибо!

Когда я запускаю программу, я получаю следующий вывод: 4000 33 100 3 33 100 423 423 100 33 200 100 4000 двойное освобождение или повреждение (fasttop) Прервано (сброшено ядро)

Это вывод, который я ожидаю: 4000 33 100 3 33 100 423 423 100 423 33 200 100

Заголовочный файл:

#ifndef MYLIST_H
#define MYLIST_H

#include <iostream>
using std::cout;
using std::endl;
using std::cin;
using std::cerr;
using std::string;

template <typename T>
class Node
{
    public:
        T m_element;

        Node<T> *m_prev;
        Node<T> *m_next;

        // Helps you make a dummy/sentinel/junk node
        Node(Node<T> *in_prev, Node<T> *in_next): 
            m_prev(in_prev), m_next(in_next){}

        Node(const T &x, Node<T> *in_prev, Node<T> *in_next): 
            m_element(x), m_prev(in_prev), m_next(in_next){}
};


template <typename T>
class MyList
{
    private:
        Node<T> *m_sentinel = nullptr;

        int m_size;

    public:
        // A list size of 0 will have 1 sentinel node.
        MyList();

        ~MyList();

        MyList<T> & operator=(const MyList<T> &source);

        MyList(const MyList<T> &source);

        T & front();

        T & back();

        void assign(int count, const T &value);

        // Default list size of 0, with one sentinel node, as above in constructor
        void clear();

        void push_front(const T &x);

        void push_back(const T &x);

        void pop_back();

        void pop_front();

        // Simplified version that only takes one int position.
        // Inserts before element at position i.
        // Not exactly like std::
        // You do NOT need a special case for 0-big lists (i.e., no if size == 0)
        // You should be able to insert in 0 big list.
        void insert(int i, const T &x);

        // Removes all elements in list that are equal to value. 
        // You do NOT need a special case for 0-big lists (i.e., no if size == 0).
        void remove(T value);

        // Removes element at position i.
        void erase(int i);

        void reverse();

        bool empty();

        int size();

        // Mimicking C++ iterator trickery from here down. 
        // You don't need to edit these two.
        int begin()
        {
            return 0;
        }

        int end()
        {
            return size();
        }
};

#include "MyList.hpp"

#endif

Файл HPP:

template <typename T>
MyList<T>::MyList()
{
  m_sentinel = new Node<T>(nullptr, nullptr);
  m_sentinel->m_next = m_sentinel;
  m_sentinel->m_prev = m_sentinel;
  m_size = 0;
}

template <typename T>
MyList<T>::~MyList()
{
  Node<T> *temp;

  for(int i = 0; i < m_size; i++)
  {
    temp = m_sentinel->m_prev;

    delete m_sentinel->m_prev;

    m_sentinel->m_prev = temp->m_prev;
  }

  delete m_sentinel;
  m_sentinel = nullptr;
}

template <typename T>
MyList<T> & MyList<T>::operator=(const MyList<T> &source)
{
  this->~MyList();

  Node<T>* tempNode = new Node<T>(nullptr, nullptr);
  tempNode = source.m_sentinel->m_next;

  m_sentinel = new Node<T>(nullptr, nullptr);
  m_sentinel->m_next = m_sentinel;
  m_sentinel->m_prev = m_sentinel;

  for(int i = 0; i < source.m_size; i++)
  {
    this->push_back(tempNode->m_element);
    tempNode = tempNode->m_next;
  }
}

template <typename T>
MyList<T>::MyList(const MyList<T> &source)
{
  *this = source;
}

template <typename T>
T & MyList<T>::front()
{
  return m_sentinel->m_next->m_element;
}

template <typename T>
T & MyList<T>::back()
{
  return m_sentinel->m_prev->m_element;
}

template <typename T>
void MyList<T>::assign(int count, const T &value)
{
  while(m_size)
  {
    this->pop_back();
  }

  for(int i = 0; i < count; i++)
  {
    this->push_back(value);
  }

  m_size = count;
}

// Default list size of 0, with one sentinel node, as above in constructor
template <typename T>
void MyList<T>::clear()
{
  while(m_size)
  {
    this->pop_back();
  }
}

template <typename T>
void MyList<T>::push_front(const T &x)
{
  Node<T> *tempNode = new Node<T>(x, m_sentinel, m_sentinel->m_next);

  m_sentinel->m_next->m_prev = tempNode;
  m_sentinel->m_next = tempNode;
  m_size++;
}
template <typename T>
void MyList<T>::push_back(const T &x)
{
  Node<T> *tempNode = new Node<T>(x, m_sentinel->m_prev, m_sentinel);

  m_sentinel->m_prev = tempNode;
  tempNode->m_prev->m_next = tempNode;
  m_size++;
}

template <typename T>
void MyList<T>::pop_back()
{
  //edit
  if(m_size != 0)
  {
    //check if temp node is needed
    //Node<T> *tempNode = m_sentinel->m_prev;


    m_sentinel->m_prev = m_sentinel->m_prev->m_prev;

    delete m_sentinel->m_prev->m_next;

    m_sentinel->m_prev->m_next = nullptr;
    m_sentinel->m_prev->m_next = m_sentinel;

    //delete tempNode;
    m_size--;
  }
}

template <typename T>
void MyList<T>::pop_front()
{
  if(m_size != 0)
  {
    m_size--;

    m_sentinel->m_next = m_sentinel->m_next->m_next;

    delete m_sentinel->m_next->m_prev;

    m_sentinel->m_next->m_prev = nullptr;
    m_sentinel->m_next->m_prev = m_sentinel;
  }
}

// Simplified version that only takes one int position.
// Inserts before element at position i.
// Not exactly like std::
// You do NOT need a special case for 0-big lists (i.e., no if size == 0)
// You should be able to insert in 0 big list.
template <typename T>
void MyList<T>::insert(int i, const T &x)
{
  if(i >= 0 && i < m_size)
  {
    Node<T> *tempNode = m_sentinel;

    for(int j = 0; j < i; j++)
    {
      tempNode = tempNode->m_next;
    }

    Node<T> *insertNode = new Node<T>(x, tempNode, tempNode->m_next);
    tempNode->m_prev->m_next = insertNode;
    tempNode->m_next->m_prev = insertNode;

    m_size++;
  }
}

// Removes all elements in list that are equal to value.
// You do NOT need a special case for 0-big lists (i.e., no if size == 0).
template <typename T>
void MyList<T>::remove(T value)
{
  Node<T> *currentNode = m_sentinel->m_next;
  Node<T> *tempNode = currentNode->m_next;

  int counter = m_size;

  for(int i = 0; i < counter; i++)
  {
    if(currentNode->m_element == value)
    {
      currentNode->m_prev->m_next = currentNode->m_next;
      currentNode->m_next->m_prev = currentNode->m_prev;

      tempNode = currentNode->m_next;

      m_size--;

      delete currentNode;
      currentNode = nullptr;

      currentNode = tempNode;
    }
    else
    {
      currentNode = currentNode->m_next;
    }
  }
}

// Removes element at position i.
template <typename T>
void MyList<T>::erase(int i)
{
  if(i >= 0 && i < m_size)
  {
    Node<T> *currentNode = m_sentinel->m_next;
    for(int j = 0; j < i; j++)
    {
      currentNode = currentNode->m_next;
    }

    currentNode->m_prev->m_next = currentNode->m_next;
    currentNode->m_next->m_prev = currentNode ->m_prev;

    delete currentNode;
    currentNode = nullptr;
    m_size--;
  }
}

template <typename T>
void MyList<T>::reverse()
{
  Node<T> *nextNode = m_sentinel->m_next;
  Node<T> *prevNode = m_sentinel->m_prev;

  for(int i = 0; i < (m_size/2); i++)
  {
    std::swap(nextNode->m_element, prevNode->m_element);
    nextNode = nextNode->m_next;
    prevNode = prevNode->m_prev;
  }
}

template <typename T>
bool MyList<T>::empty()
{
  if(m_size==0)
  {
    return true;
  }
  else
  {
    return false;
  }
}

template <typename T>
int MyList<T>::size()
{
  return m_size;
}

Драйвер для проверки, работает ли функция MyList как std :: list:

#include <list>
#include "MyList.h"

int main()
{
    MyList<int> l;
    //std::list<int> l;

    l.push_back(4000);
    l.push_back(200);
    l.push_back(100);
    cout << l.front() << endl;
    l.front() = 33;
    cout << l.front() << endl;
    cout << l.back() << endl;

        cout << l.size() << endl;
    l.push_back(4000);
    l.push_back(200);
    l.push_back(100);
    cout << l.front() << endl;
    cout << l.back() << endl;

    l.push_front(423);

    cout << l.front() << endl;

    MyList<int> sink;
    sink = l;
    cout << sink.front() << endl;
    cout << sink.back() << endl;

    l.insert(l.begin(), 3);
    l.insert(l.end(), 20);
    l.pop_front();
    l.reverse();

    int j = 0;
    for(auto i = 0; i < l.size(); i++)
    {
        cout << l.back() << endl;
        l.pop_back();
        j++;
    }
    return 0;
}

Спасибо!

ОБНОВЛЕННЫЙ КОНСТРУКТОР КОПИРАТОРА И ОПЕРАТОР НАЗНАЧЕНИЯ

template <typename T>
MyList<T> & MyList<T>::operator=(const MyList<T> &source)
{
  MyList<T> temp(source);
  std::swap(temp.m_sentinel, m_sentinel);
  return *this;
}
template <typename T>
MyList<T>::MyList(const MyList<T> &source)
{
  Node<T> *temp = source.m_sentinel;
  m_sentinel = nullptr;
  while(temp != nullptr)
  {
    push_back(temp->m_element);
  }
}

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

...