Console crashes when creating linked list class

All the code barring the "remove" function in LinkedL seems to work. When I try to remove a node from the linked list, the console crashes. Can anyone help me solve this problem because no explicit error is thrown which makes me think its a runtime issue as it compiles OK.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#ifndef NODE_H
#define NODE_H

template <typename T>
class Node
{
private:
	T m_Data;
	Node<T>* m_Next;
	Node<T>* m_Prev;
public:
	Node();
	Node(const T& m_Data);
	~Node();

	Node<T>* getNext() const;
	Node<T>* getPrev() const;
	T& getData();

	void setNext(Node<T>* n);
	void setPrev( Node<T>* p);
	void setData(const T& data);
};

template <typename T>
Node<T>::Node()
{
	m_Data = T();
	m_Next = 0;
	m_Prev = 0;
}

template <typename T>
Node<T>::Node(const T& data)
{
	m_Data = data;
	m_Next = 0;
	m_Prev = 0;
}

template <typename T>
Node<T>::~Node()
{
	delete m_Next;
	delete m_Prev;

	m_Next = 0;
	m_Prev = 0;
}

template <typename T>
Node<T>* Node<T>::getNext() const {
	return m_Next;
}

template <typename T>
Node<T>* Node<T>::getPrev() const {
	return m_Prev;
}

template <typename T>
void Node<T>::setNext(Node<T>* n) {
	m_Next = n;
}

template <typename T>
void Node<T>::setPrev(Node<T>* p) {
	m_Prev = p;
}

template <typename T>
void Node<T>::setData(const T& data) {
	m_Data = data;
}

template <typename T>
T& Node<T>::getData() {
	return m_Data;
}


#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"
#include <iostream>

using namespace std; 

template <typename T>
class LinkedL
{
public:
	LinkedL();
	~LinkedL();

	bool isEmpty();
	void insertFirst(const T& data);
	void insertLast(const T& data);
	void insertAfter(const T& key, const T& data);
	int getSize()const;
	Node<T>* getNode(int i) const;
	bool remove(int i);

	T& operator[](int i);

private:
	Node<T>* m_First;
	Node<T>* m_Last;
	int m_Size;
};

template <typename T>
LinkedL<T>::LinkedL()
{
	m_First = 0;
	m_Last = 0;
	m_Size = 0;
}

template <typename T>
LinkedL<T>::~LinkedL()
{
	if (m_First != 0) {
		Node<T>* current = m_First;
		while (current != 0) {
			Node<T>* oldNode = current;
			current = current->getNext();
			delete oldNode;
			oldNode = 0;
		}
	}
}

template <typename T>
bool LinkedL<T>::isEmpty() {
	if (m_First == 0) {
		return true;
	} return false; 
}

template <typename T>
void LinkedL<T>::insertFirst(const T& data) {
	Node<T>* newNode = new Node<T>(data);
	if (isEmpty()) {
		m_First = newNode;
		m_Last = newNode;
	}
	else {
		m_First->setPrev(newNode);
		newNode->setNext(m_First);
		m_First = newNode;
	}
	m_Size;
}

template <typename T>
void LinkedL<T>::insertAfter(const T& key, const T& data) {
	if (isEmpty()) {
		return;
	} 
	Node<T>* current=0;
	for (int i = 0; i <= this->getSize(); i++) {
		if (this->operator[](i) == key) {
			current = this->getNode(i);
		}
	}
	Node<T>* newNode = new Node<T>(data);
	if (current == 0) {
		cout << "Node could not be found." << endl;
		return;
	}
	else if (current==m_Last) {
		
		m_Last = newNode;
		newNode->setNext(0);
	}
	else {
		current->getNext()->setPrev(newNode);
		newNode->setNext(current->getNext());
	}
	current->setNext(newNode);
		newNode->setPrev(current);
}

template <typename T>
int LinkedL<T>::getSize() const{
	return m_Size;
}

template <typename T>
void LinkedL<T>::insertLast(const T& data) {
	Node<T>* newNode = new Node<T>(data);
	if (isEmpty()) {
		m_Last = newNode;
		m_First = newNode;
	}
	else {
		m_Last->setNext(newNode);
		newNode->setPrev(m_Last);
		m_Last = newNode;
	}
	m_Size++;
}

template <typename T>
T& LinkedL<T>::operator[](int i) {
	int counter = 0;
	Node<T>* current = m_First;

	while (true) {
		if (counter == i) {
			return current->getData();
		}
		current = current->getNext();
		counter++;
	}
}

template <typename T>
Node<T>* LinkedL<T>::getNode(int i) const{
	int counter = 0;
	Node<T>* current = m_First;
	if (i<0 && i>this->getSize()) {
		return nullptr;
	}
	while (true) {
		if (counter == i) {
			return current;
		}
		current = current->getNext();
		counter++;
	}
}

template <typename T>
bool LinkedL<T>::remove(int i) {

	if (isEmpty() || i<0 || i>getSize()) {
		cout << "No nodes to remove in specified index" << endl;
		return false;
	}
	else if (getNode(i - 1) != 0 && getNode(i + 1) != 0) {
		getNode(i)->getPrev()->setNext(getNode(i)->getNext());
		getNode(i)->getNext()->setPrev(getNode(i)->getPrev());
		delete getNode(i);
		return true;
	}
	else if (i==0) { //remove first element
		getNode(i + 1)->setPrev(0);
		m_First = getNode(i + 1);
		delete getNode(i);
		return true;
	}
	else {//remove last element
		getNode(i - 1)->setNext(0);
		m_First = getNode(i - 1);
		delete getNode(i);
		return true;
	}
}

#endif // !LINKEDLIST_H


#include <iostream>
#include "LinkedL.h"

using std::cout;
using std::endl;



int main() {

	LinkedL<int> list;
	list.insertFirst(31);
	list.insertLast(23);
	list.insertAfter(23, 67);
	list.insertAfter(23, 45);
	list.remove(1);
	cout << list[0] <<endl;
	system("PAUSE");
}	
The problem in the remove(...) function is the use of getNode(i).

The point is that getNode(i) searches an existing node. As soon as you remove the node from the list (line 243) it cannot not be found and the wrong node (line 245) will be deleted.
ahhhh i get it. thanks. could you suggest a solution?

I was thinking of this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool LinkedL<T>::remove(int i) {
	Node<T>* prev = getNode(i - 1);
	Node<T>* next = getNode(i + 1);

	if (isEmpty() || i<0 || i>getSize()) {
		cout << "No nodes to remove in specified index" << endl;
		return false;
	}
	else if (prev != 0 && next != 0) {
		delete getNode(i);
		prev->setNext(next);
		next->setPrev(prev);
		return true;
	}


But this doesnt work either

I jsut want to see if I can make a solution with my current functions
Last edited on
The next problem is this:
1
2
3
4
5
6
7
8
9
template <typename T>
Node<T>::~Node()
{
	delete m_Next;
	delete m_Prev;

	m_Next = 0;
	m_Prev = 0;
}
Once you delete a single node you delete the whole list recursively.
Ok that does make sense. It's because it literally keeps on deleting the next pointers to nodes.
I think I have a good idea on how to execute the remove method as you can apparently set the getNode(i) equal to a node ptr variable and deleting the node ptr variable will delete the shared memory as well.

But what should i do with the destructor? Like I would need to delete the node and free memory but then deleting the nodes deletes all the next/prev elements.
I'm looking to approach it like in this document:

http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/doubly_linked.html

But I'm wondering how the dtor of node would look like because as you said it would recursively delete the whole list.

I solved the problem like this:

1
2
3
4
5
6
7
8
9
10
11
12
	Node<T>* iNode = getNode(i);

	if (isEmpty() || i<0 || i>getSize()) {
		cout << "No nodes to remove in specified index" << endl;
		return false;
	}
	else if (getNode(i-1) != 0 && getNode(i+1) != 0) {
		getNode(i - 1)->setNext(getNode(i + 1));
		getNode(i + 1)->setPrev(getNode(i - 1));
		iNode->setNext(T());
		iNode->setPrev(T());
		delete iNode;


but I have a feeling this isnt a good solution as the delete should be able to do all the work.
But I'm wondering how the dtor of node would look like because as you said it would recursively delete the whole list.
It doesn't make sense to have a destructor for node at all. You could make Node a private class of LinkedL because it is not used anywhere else.

I would suggest that you remove the public setter/getter of Node and make the member variables public because otherwise you have just overhead without gain.

Further i would suggest that you use getNode(...) only once at the beginning. The rest can be done with Prev/Next.
Topic archived. No new replies allowed.