c++中动态分配的链表,异常后如何防止内存泄漏? [英] Dynamically allocated linked list in c++.What to do after exception to prevent memory leak?

查看:37
本文介绍了c++中动态分配的链表,异常后如何防止内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢用c++实现链表,在添加新节点时我动态分配它,如果某些分配失败,我希望我的程序停止执行.

在新节点"失败后抛出异常,所以我必须在异常处理程序中显式调用析构函数.我该如何处理这种情况以防止内存泄漏?这是我写的代码

LinkedList.h

#pragma once#include #include 使用命名空间标准;类链表{上市:类迭代器;私人的:类节点{友元类迭代器;好友类 LinkedList;字符* m_word;节点 *m_next;节点(const char* word,Node* next = NULL,Node* prev = NULL);〜节点();};节点 *m_head,*m_tail;size_t m_num;上市:LinkedList():m_head(NULL),m_tail(NULL),m_num(0){};〜链表();链表&addFirst(const char* word);链表&addLast(const char* word);迭代器擦除(Iterator& it);迭代器开始();迭代器结束();迭代器 find(const char* word);size_t size()const{return m_num;};无效打印();友元类迭代器;类迭代器{链表&m_list;节点 *m_prev,*m_cur;好友类 LinkedList;无效的下一个();void setLast(){m_cur = NULL,m_prev = m_list.m_tail;}上市:迭代器(LinkedList&linkedList):m_list(linkedList),m_prev(NULL),m_cur(linkedList.m_head){}迭代器&运算符++();字符*运算符*();bool 运算符 != (Iterator& 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 = 下一个;如果(上一个!= NULL)prev->m_next = this;}LinkedList::Node::~Node(){删除[] m_word;}LinkedList::~LinkedList(void){for(Iterator it = begin();it != end();)擦除(它);}链表&LinkedList::addFirst(const char* word){Node* node = new Node(word,NULL,m_head);m_head = 节点;如果(m_tail == NULL)m_tail = m_head;++m_num;返回 *this;}链表&LinkedList::addLast(const char*word){如果(m_head == NULL)添加第一个(字);别的{Node* node = new Node(word,m_tail,NULL);m_tail = 节点;}++m_num;返回 *this;}LinkedList::Iterator LinkedList::begin(){迭代器 it(*this);把它返还;}LinkedList::Iterator LinkedList::end(){迭代器 it(*this);it.setLast();把它返还;}LinkedList::Iterator LinkedList::erase(LinkedList::Iterator& it){if(it.m_cur != NULL){节点* tmp = it.m_cur;if(it.m_prev != NULL)it.m_cur = it.m_prev->m_next = tmp->m_next;别的it.m_cur = it.m_list.m_head = tmp->m_next;if(tmp == it.m_list.m_tail)it.m_list.m_tail = NULL;删除tmp;--m_num;}把它返还;}LinkedList::Iterator LinkedList::find(const char* word){迭代器 it = begin();for(;it != end();++it){if(!strcmp(it.m_cur->m_word,word))休息;}把它返还;}void LinkedList::Iterator::next(){如果(m_cur != NULL){m_prev = m_cur;m_cur = m_cur->m_next;}别的m_prev = NULL;返回;}void LinkedList::print(){for(Iterator it = begin();it !=end();++it)cout<<it.m_cur->m_word;}LinkedList::Iterator&LinkedList::Iterator::operator ++(){下一个();返回 *this;}char* LinkedList::Iterator::operator *(){返回 m_cur->m_word;}//int main()//{//链表 ll;//ll.addFirst("1");//ll.addFirst("2");//ll.addLast("3");//ll.addLast("4");//LinkedList::Iterator it = ll.find("5");//返回 0;//}

解决方案

新节点"失败后抛出异常.

所以我必须在异常处理程序中显式调用析构函数.

没有.如果构造函数没有完成,则不能调用析构函数(对象从未创建).

<块引用>

我该如何处理这种情况以防止内存泄漏?

如果异常是在 new (std::bad_alloc) 中抛出的,那么你不需要做什么.

如果异常是从构造函数抛出的.然后每个完全构造的成员都会自动调用其析构函数.所以你不需要担心普通会员.如果您的任何成员是指针(已在构造函数中初始化),那么您需要确保它们被删除(这就是为什么您不希望对象中包含 RAW 指针(您需要智能指针)).

这么说.您没有使用智能指针,但我看不到任何明显的泄漏.

但是您的类中拥有一个 RAW 指针.你还没有读过 3 的规则(查一查).目前因为你不遵守规则 3,下面的代码会崩溃.

void myCode(){链表列表1;list1.addFirst("马丁");链表 list2(list1);}

I like to implement linked list in c++ ,while adding new node I dynamically allocate it, if some allocation fails I would like my program to stop the execution.

After the "new Node" fails the exception is thrown so do I have to call the destructor explicitly in the exception handler. how can I deal with this situation in order to prevent memory leak? Here is my code that I have written

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();
    LinkedList& addFirst(const char* word);
    LinkedList& addLast(const char* word);
    Iterator erase(Iterator& it);
    Iterator begin();
    Iterator end();
    Iterator find(const char* word);
    size_t size()const{return m_num;};
    void print();

    friend class Iterator;
    class Iterator
    {
        LinkedList& 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(LinkedList& linkedList):m_list(linkedList),m_prev(NULL),m_cur(linkedList.m_head){}
        Iterator& operator++();
        char* operator*();
        bool operator != (Iterator& 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);
}
LinkedList& 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;
}
LinkedList& 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::Iterator& 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::Iterator& 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;
//}

解决方案

After the "new Node" fails the exception is thrown.

so do I have to call the destructor explicitly in the exception handler.

No. If the constructor did not finish then you can not call the destructor (the object was never created).

how can I deal with this situation in order to prevent memory leak?

If the exception is thrown in new (std::bad_alloc) then there is nothing you need to do.

If the exception is thrown from the constructor. Then every fully constructed member will have its destructor called automatically. So you don't need to worry about normal members. If any of your members are pointers (that have been initialized in the constructor) then you need to make sure that these get deleted (which is why you don't want RAW pointers in your object (you want smart pointers)).

Saying that. You do not use smart pointers but I can't see any obvious leaks.

But you have a RAW pointer in your class that is owned. You have not read about the rule of 3 (look it up). Currently because you do not obey the rule of 3 the follwoing code will crash.

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

    LinkedList    list2(list1);
}

这篇关于c++中动态分配的链表,异常后如何防止内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆