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(co开发者_C百科nst 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);
}
If new
is failing then you don't have to worry about memory leak, because you haven't allocated anything yet. You can just log that error message if needed and get ahead with the existing linked list.
I don't see any exception handler there. iammilind's answer is fair, but even if you don't want to log the failure, you must write an exception handler, because if you are not, the exception goes up to higher context, it can stop your program with a well known message that you can see in debuggers: UNHANDLED EXTEPTION at .... I suspect you tought that under the term memory-leak.
精彩评论