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

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

问题描述

我喜欢在c ++中实现链表,而添加新的节点我动态分配它,
如果一些分配失败,我想我的程序停止执行。



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



LinkedList.h

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

class LinkedList
{
public:
class Iterator;
private:
class Node
{
friends 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);
迭代器擦除(迭代器& it);
迭代器begin();
迭代器结束();
迭代器find(const char * word);
size_t size()const {return m_num;};
void print();

friend class迭代器;
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 .m_head){}
迭代器& operator ++();
char * operator *();
bool operator!=(Iterator& it){return(m_cur!= it.m_cur || m_prev!= it.m_prev);}
};
};

LinkedList.cpp

  #includeLinkedList.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()
{
迭代器it(* this);
return it;
}
LinkedList :: Iterator LinkedList :: end()
{
迭代器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)
<< 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;
//}


解决方案


在new Node失败后,抛出异常。



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


否。如果构造函数没有完成,那么你不能调用析构函数(对象从未创建)。


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


如果在新的(std :: bad_alloc)中抛出异常, do。



如果从构造函数抛出异常。然后每个完全构造的成员将自动调用它的析构函数。所以你不需要担心正常会员。如果你的任何成员是指针(已经在构造函数中初始化),那么你需要确保这些被删除(这就是为什么你不想要RAW指针在你的对象(你想要的智能指针))。 p>

说。你不使用智能指针,但我看不到任何明显的泄漏。



但你有一个RAW指针在你的类拥有。你没有读过3的规则(看起来)。因为你不遵守规则3,以下代码将会崩溃。

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

LinkedList 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天全站免登陆