Динамически выделяемый связанный список в c .Что делать после исключения, чтобы предотвратить утечку памяти?

#c #dynamic #linked-list

#c #динамический #связанный список

Вопрос:

Мне нравится реализовывать связанный список на c , при добавлении нового узла я динамически выделяю его, если какое-то выделение завершается неудачей, я бы хотел, чтобы моя программа остановила выполнение.

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

LinkedList.h

 #pragma once
#include <iostream>
#include <string.h>
using namespace std;

class LinkedList
{
public:
    class Iterator; 
private:
    class Node
    {
        friend class Iterator;
        friend class LinkedList;
        char* m_word;
        Node *m_next;
        Node(const char* word,Node* next = NULL,Node* prev = NULL);
        ~Node();
    };
    Node *m_head,*m_tail;
    size_t m_num;
public:
    LinkedList():m_head(NULL),m_tail(NULL),m_num(0){};
    ~LinkedList();
    LinkedListamp; addFirst(const char* word);
    LinkedListamp; addLast(const char* word);
    Iterator erase(Iteratoramp; it);
    Iterator begin();
    Iterator end();
    Iterator find(const char* word);
    size_t size()const{return m_num;};
    void print();

    friend class Iterator;
    class Iterator
    {
        LinkedListamp; m_list;
        Node *m_prev,*m_cur;
        friend class LinkedList;
        void next();
        void setLast(){m_cur = NULL,m_prev = m_list.m_tail;}
    public:
        Iterator(LinkedListamp; linkedList):m_list(linkedList),m_prev(NULL),m_cur(linkedList.m_head){}
        Iteratoramp; operator  ();
        char* operator*();
        bool operator != (Iteratoramp; it){return (m_cur != it.m_cur || m_prev != it.m_prev);}
    };
};
  

LinkedList.cpp

 #include "LinkedList.h"


LinkedList::Node::Node(const char* word,LinkedList::Node* prev,LinkedList::Node *next)
{
    char* tmpWord = new char[strlen(word) 1];
    strcpy(tmpWord,word);
    m_word = tmpWord;
    m_next = next;
    if(prev != NULL)
        prev->m_next = this;
}
LinkedList::Node::~Node()
{
    delete[] m_word;
}

LinkedList::~LinkedList(void)
{
    for(Iterator it = begin();it != end();)
        erase(it);
}
LinkedListamp; LinkedList::addFirst(const char* word)
{
    Node* node = new Node(word,NULL,m_head);
    m_head = node;
    if(m_tail == NULL)
        m_tail = m_head;
      m_num;
    return *this;
}
LinkedListamp; LinkedList::addLast(const char*word)
{
    if(m_head == NULL)
        addFirst(word);
    else
    {
        Node* node = new Node(word,m_tail,NULL);
        m_tail = node;
    }
      m_num;
    return *this;
}
LinkedList::Iterator LinkedList::begin()
{
    Iterator it(*this);
    return it;
}
LinkedList::Iterator LinkedList::end()
{
    Iterator it(*this);
    it.setLast();
    return it;
}
LinkedList::Iterator LinkedList::erase(LinkedList::Iteratoramp; it)
{
    if(it.m_cur != NULL)
    {
        Node* tmp = it.m_cur;
        if(it.m_prev != NULL)
            it.m_cur = it.m_prev->m_next = tmp->m_next;
        else
            it.m_cur = it.m_list.m_head = tmp->m_next;
        if(tmp == it.m_list.m_tail)
            it.m_list.m_tail = NULL;
        delete tmp;
        --m_num;
    }
    return it;
}
LinkedList::Iterator LinkedList::find(const char* word)
{
    Iterator it = begin();
    for(;it != end();  it)
    {
        if(!strcmp(it.m_cur->m_word,word))
            break;
    }
    return it;
}

void LinkedList::Iterator::next()
{
    if(m_cur != NULL)
    {
        m_prev = m_cur;
        m_cur = m_cur->m_next;
    }
    else
        m_prev = NULL;
    return;
}
void LinkedList::print()
{
    for(Iterator it = begin();it !=end();  it)
        cout << it.m_cur->m_word;
}
LinkedList::Iteratoramp; LinkedList::Iterator::operator   ()
{
    next();
    return *this;
}
char* LinkedList::Iterator::operator *()
{
    return m_cur->m_word;
}

//int main()
//{
//  LinkedList ll;
//  ll.addFirst("1");
//  ll.addFirst("2");
//  ll.addLast("3");
//  ll.addLast("4");
//  LinkedList::Iterator it = ll.find("5");
//  return 0;
//}
  

Комментарии:

1. Вы снова опубликовали свой вопрос? Я подумал, почему мой ответ не появляется ! 🙂

2. Пожалуйста, не задавайте один и тот же вопрос дважды — это отвлекает людей, которые в противном случае думали бы над ответами.

3. Если вы хотите сохранить строку, почему бы не использовать std::string?

Ответ №1:

После сбоя «нового узла» генерируется исключение.

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

Нет. Если конструктор не завершился, то вы не можете вызвать деструктор (объект так и не был создан).

как я могу справиться с этой ситуацией, чтобы предотвратить утечку памяти?

Если исключение генерируется в new (std::bad_alloc), то вам ничего не нужно делать.

Если исключение выдается из конструктора. Тогда для каждого полностью созданного элемента будет автоматически вызываться деструктор. Таким образом, вам не нужно беспокоиться об обычных членах. Если какие-либо из ваших элементов являются указателями (которые были инициализированы в конструкторе), то вам нужно убедиться, что они будут удалены (вот почему вы не хотите, чтобы необработанные указатели были в вашем объекте (вам нужны интеллектуальные указатели)).

Говоря это. Вы не используете интеллектуальные указатели, но я не вижу никаких очевидных утечек.

Но у вас есть НЕОБРАБОТАННЫЙ указатель в вашем классе, который принадлежит. Вы не читали о правиле 3 (посмотрите его). В настоящее время, поскольку вы не подчиняетесь правилу 3, следующий код завершит работу с ошибкой.

 void myCode()
{
    LinkedList    list1;
    list1.addFirst("Martin");

    LinkedList    list2(list1);
}
  

Ответ №2:

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

Ответ №3:

Я не вижу там никакого обработчика исключений. ответ iammilind справедлив, но даже если вы не хотите регистрировать сбой, вы должны написать обработчик исключений, потому что в противном случае исключение переходит в более высокий контекст, это может остановить вашу программу с помощью хорошо известного сообщения, которое вы можете увидеть в debuggers: НЕОБРАБОТАННОЕ РАСШИРЕНИЕ at …. Я подозреваю, что вы использовали это под термином «утечка памяти».