Linked list append

I made a linkedlist class and everything works except for the append function. When the program exits and the destructor is called, there is an "assertion error".

The append function connects the tail node of the first list to the head node of the second list and sets the tail to point to second list's tail. Then I delete the second list. The problem is that they point to the same list. So when I delete the second list then it is going to lose the nodes and the tail pointer of the first list would be pointing to a deleted value.

So how should I implement the append function?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void append(linkedlist<ItemType> attach) {
		
		if (head == NULL) {
			head = attach.head;
			tail = attach.tail;
			return;
		}
		else if (attach.head == NULL) {
			return;
		}
		
		else {
			// set links at tail of first and head of second
			tail->next = attach.head;
			attach.head->prev = tail;
			// synchronize the heads and tails
			tail = attach.tail;
			attach.clear();
		}
	}


here is the rest of the class if you want to see it as well. append is at the bottom.

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
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
template <typename ItemType>

class linkedlist {

private:

	struct Node {
		ItemType item;
		Node* next;
		Node* prev;
	};
	Node* head;
	Node* tail;
	unsigned size;
public:

	linkedlist() {
		head = NULL;
		tail = NULL;
		size = 0;
	}

	~linkedlist() {
		clear();
	}

	Node* first() {
		return head;
	}

	void insert(int index, const ItemType& item)
	{
		if (index > size) return; // if index is too high

		if (size == 0 && index == 0) { // add first node
			Node* temp = new Node();

			temp->item = item;
			temp->prev = NULL;
			temp->next = NULL;

			head = temp;
			tail = temp;
			size++;
		}

		else if (index == 0 && size) { // add node to beginning
			Node* temp = new Node();

			temp->item = item;
			temp->prev = NULL;
			temp->next = head;

			head->prev = temp;
			head = temp;
			size++;
		}

		else if (index == size) { // add node to end
			Node* temp = new Node();

			temp->item = item;
			temp->prev = tail;
			temp->next = NULL;

			tail->next = temp;
			tail = temp;
			size++;
		}

		else insert_middle(index, item);
	}

	void insert_middle(int index, const ItemType& item)
	{
		if (index < size) { // add node to middle
			Node* temp = new Node();
			Node* pos = NULL;
			temp->item = item;

			if (index < (size >> 1)) {
				pos = head;
				for (int i = 0; i < index; i++) {
					pos = pos->next;
				}
			}
			else {
				pos = tail;
				for (int i = 0; i < (size - index); i++) {
					pos = pos->next;
				}
			}

			// set new node's pointers
			temp->next = pos;
			temp->prev = pos->prev;
			// pointers set to new node
			pos->prev->next = temp;
			pos->prev = temp;


			size++;
		}
	}

	ItemType mem_free(int index, Node* pos)// 2nd half of remove function (to reduce complexity)
	{
		ItemType data = pos->item;
		// for list size 1
		if (size == 1) {
			tail = NULL;
			head = NULL;
		}
		// set next and prev nodes to point to each other
		else if (pos == tail) { // delete last node
			tail = pos->prev;
			pos->prev->next = pos->next;
		}
		else if (pos == head) { // delete first node
			head = pos->next;
			pos->next->prev = pos->prev;
		}
		else { // delete middle node
			pos->prev->next = pos->next;
			pos->next->prev = pos->prev;
		}
		delete pos;

		size--;

		return data;
	}

	ItemType remove(int index) // remove for 235
	{
		if (index < 0 || index >= size) {
			return ItemType();
		}

		Node* pos = NULL;
		// finds the node at the index
		if (index <= (size >> 1)) {
			pos = head;
			for (int i = 0; i < index; i++) {
				pos = pos->next;
			}
		}
		else {
			pos = tail;
			for (int i = 1; i < (size - index); i++) {
				pos = pos->prev;
			}
		}

		ItemType thing = mem_free(index, pos);
		return thing;
	}

	int find_pos(const ItemType& item)
	{
		Node* pos = head;
		for (int i = 0; i < size; i++) {
			if (pos->item == item) {
				return i;
			}
			pos = pos->next;
		}
		return -1;
	}

	string print()
	{
		Node* temp = head;
		stringstream ss;
		for (int i = 0; i < size; i++)
		{
			ss << "node " << i << ": " << temp->item << endl; 
                        // middle nodes
			temp = temp->next;
		}
		return ss.str();
	}

	void clear() // removes all items from the list
	{
		Node *second, *first = head;
		while (first != NULL) {
			second = first->next;
			delete first;
			first = second;
		}
		size = 0;
		head = NULL;
		tail = NULL;
	}

	void sortedInsert(const ItemType& item) {
		
		if (!size) { // for an empty list
			Node* temp = new Node();

			temp->item = item;
			temp->prev = NULL;
			temp->next = NULL;

			head = temp;
			tail = temp;
			size++;
		}
		else if (size) {
			
			if (head->item > item) { // insert smallest node
				Node* temp = new Node();
				
				temp->next = head;
				temp->prev = NULL;
				temp->item = item;
				
				head->prev = temp;
				head = temp;
				size++;
			}
			else if (tail->item < item) { // insert largest node
				Node* temp = new Node();

				temp->prev = tail;
				temp->next = NULL;
				temp->item = item;

				tail->next = temp;
				tail = temp;
				size++;
			}
			else { // insert middle node
				Node* pos = head;
				for (int i = 0; i < size; ++i) {
					if (pos->item < item) {
						pos = pos->next;
					}
					else break;
				}
				Node* temp = new Node();

				//set new nodes' pointers
				temp->next = pos;
				temp->prev = pos->prev;
				temp->item = item;

				//set next/prev nodes' pointers to new node
				temp->prev->next = temp;
				pos->prev = temp;
				size++;
			}
		}
	}

	/*linkedlist<ItemType> sort(Node* first) {
		linkedlist<ItemType> list_1;
		if (first->next == NULL && first->prev == NULL) {
			list_1.push(first->item);
		}
		else if (first->prev == NULL && first->next->next == NULL) {
			if (first->item < first->next->item) {
				list_1.push(first->next->item);
				list_1.push(first->item);
			}
		}
		else {
			Node* pos = first;
			while (pos->next != NULL) {
				list_1.sortedInsert(pos->item);
				pos = pos->next;
			}
		}
		return list_1;
	}*/

	int getLength() {
		return size;
	}

	void sort(linkedlist<ItemType>& toSort) { // slow sort function, couldn't get the one above to work
		linkedlist<ItemType> two;
		Node* temp = head;

		vector<ItemType> v;
		for (int i = 0; i < size; ++i) {
			v.push_back(temp->item);
			temp = temp->next;
		}
		toSort.clear();
		std::sort(v.begin(), v.begin()+size);
		for (int i = v.size() - 1; i >= 0; --i) {
			toSort.sortedInsert(v[i]);
		}
	}

	void append(linkedlist<ItemType> attach) {
		
		if (head == NULL) {
			head = attach.head;
			tail = attach.tail;
			return;
		}
		else if (attach.head == NULL) {
			return;
		}
		
		else {
			// set links at tail of first and head of second
			tail->next = attach.head;
			attach.head->prev = tail;
			// synchronize the heads and tails
			tail = attach.tail;
			attach.clear();
		}
	}

};
Two points:
1
2
3
4
5
void T::append( T attach )
{
// make this point to nodes of attach
  attach.clear();
}

When we use it:
1
2
3
T a;
T b;
a.append( b );

Lets pseudo-inline the function call:
1
2
3
4
5
6
7
T a;
T b;
// start append
T attach = b;
// make 'a' point to nodes of attach
attach.clear();
// end append 


If 'b' had a node before calling append(), then 'b' points to that node, 'a' points to that node, and 'attach' points to that same node before calling clear(). Both 'a' and 'b' will point to deallocated space in the end.

It appears that you want to move nodes from 'b' to 'a'. If they are moved, then they should not be deleted.

The first point was the by value parameter. Calling append() invokes copy constructor. The default copy constructor that the compiler makes for you, since you don't define one. The default copies pointers, not the values that they point to.
1
2
3
4
5
U * x = ...;
// The default copy:
U * y = x;
// Explicit deep copy:
U * y = new U( *x );


The Rule of Three:
If a class owns dynamic memory, then it should implement (1) copy constructor, (2) copy assignment, and (3) destructor. The compiler generated defaults will fail.
Topic archived. No new replies allowed.