Linked List (destructor/assignment operator)

Oct 4, 2016 at 11:31am
Hello guys, I'm starting to learn about classes and created a Linked List using it, it looks like this;

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
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

class Linked{
private:
    struct node{
    int _x;
    node *_next;
    };
    node *_head = NULL;
public:
    Linked()
    {
    node *newNode = new node;
    newNode->_next = _head;
    _head = newNode;
    newNode->_x = rand()%50;
    }
    ~Linked()
    {
        while (_head != NULL){
            delete _head;
            _head = _head->_next;
            cout << "Deleting\n";
        }
    }


    void addNode(int num)
    {
    node *newNode = new node;
    newNode->_next = _head;
    newNode->_x = num;
    _head = newNode;
    }
    void getNumber()
    {
    node *_tmp = _head;
    while (_tmp != NULL)
    {
    cout << _tmp->_x << ",";
    _tmp = _tmp->_next;
    }
    cout << "\n";
    }
};

int main (){
srand(time(NULL));

int option, num;
Linked p1,p2;

while (1){
cin >> num;
p1.addNode(num);
p2.addNode(num+1);

p1.getNumber();
p2.getNumber();

if (num == 128){
    p1 = p2;
    break;
}
}
}


I have read quite some, and have some questions regarding destruction;

1. I have read that my destructor could just contain a "delete _head" cause it will start a recursive call until it reaches NULL, but while I try that, the cout statement (inside of the destructor) just happens once, not depending on how many nodes are in the linked list, which surprises me? Also how important is it to set the _head = NULL after each node deletion?

2. I'm trying to understand as why p1 = p2; doesn't crash the program once terminated, cause the destructor should be ran twice on the same memories? I don't understand why it DOESN'T crash!

(I'm basically in this case trying to learn about when it would be useful to use assignment operators, but as this example doesn't crash the program, I am very confused!)


Oct 5, 2016 at 4:58pm
For 1):
You're creating two liked lists but each only has one node. The destructor is therefore called only once to delete the one node in the linked list. Make sense?
For 2):
No destructors are called until main() ends. Just before, when you assign p1 = p2; no classes have been destructed. Why would that cause an error?
Oct 5, 2016 at 7:12pm
1. When I made it look like
1
2
3
4
5
~Linked()
    {
  delete _head;
    cout << "Deleting\n";
}

It didn't print out a "Deleting" for each node, which is why I changed to what I have now.
(it output this when using a destructor which just contains delete _head);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Success	time: 0 memory: 3472 signal:0
100,20,
101,27,
200,100,20,
201,101,27,
300,200,100,20,
301,201,101,27,
400,300,200,100,20,
401,301,201,101,27,
500,400,300,200,100,20,
501,401,301,201,101,27,
128,500,400,300,200,100,20,
129,501,401,301,201,101,27,
DeletingDeleting

And it doesn't just have "one node", the while loop makes me able to add multiple nodes if you missed that:P

2.) Hmm could you give me an example of where an assignment operator is required? I'm having a hard time understanding that, cause my assignings now work error free:\, and I believe I'd understand it better by reproducing such a scenario .
Last edited on Oct 5, 2016 at 7:15pm
Oct 5, 2016 at 7:26pm
Assigning the top node of a linked list will not copy the entire list. Only the top node. So "assigning a linked list" does not make sense in this respect.
Oct 5, 2016 at 7:49pm
Hmm, Ok!

But if the destructor gets ran, the part I don't understand is;
Obj1 = Obj2;
Obj1 now has the same pointer to node values as Obj2,

#1: at the end of main, destructor for Obj1 gets ran, the pointer is now invalid cause it got deleted.
#2: now destructor for Obj2 gets ran, destructor tries to delete an invalid pointer? Shouldn't it crash?

This is the part that I struggle with understanding, along with what really happens with Obj1's memory, as it never gets cleaned cause you assign it to Obj2, before a destructor has been ran on it.

Last edited on Oct 5, 2016 at 7:50pm
Oct 5, 2016 at 9:00pm
Hold on. In #1 why is Obj1 invalid? It still points to Obj2.
Oct 5, 2016 at 9:11pm
Yeah? it contains the same information as Obj2 after the assignment, but after the memory deletion, does it?
I thus understood it like this;

1
2
3
4
5
int main()
{
obj1 = obj2;

} (destructor for obj1 runs, deletes memory of all nodes of Obj2)
--> after obj1 deletion, (destructor for obj2 runs, deletes all memory of all nodes of Obj2 (which already are deleted?) thus program should crash cause of deleting memory which already is deleted?
Last edited on Oct 5, 2016 at 9:18pm
Oct 5, 2016 at 9:20pm
Ah ha. Now I know. You were assigning a class to a class. This does not do a deep copy, but a shallow copy. This basically means that you're assigning a class and therefore creating a new one with the same values. Not the same actual memory addresses.

Does this answer your question?
Oct 5, 2016 at 9:43pm
Oh yeah, that makes sense then! I thought the copies copied the memory adresses aswell, I was very confused!

But it leads me to my next question;

"Implement a vector replacement that operates only on integers, vectorOfInt. Your class should have the following interface:"

• A no-argument constructor that allocates a 32-element vector
• A constructor that takes an initial size as the argument
• A method get, taking an index and returning the value at that index
• A method set, that takes an index and a value, and sets the value at that index
• A method pushback that adds an element to the end of the array, resizing if necessary
• A method pushfront that adds an element to the beginning of the array
• A copy constructor and assignment operator

I have programmed the non bolded(I can post a separate thread if needed with the code), but now I am confused of why an assignment operator would even be needed for this exercise? If it always does a shallow copy from class to class by default(?), thus no reason for it?

Thanks for your help.
Last edited on Oct 5, 2016 at 9:49pm
Oct 6, 2016 at 3:58pm
Yes, please post the code you have so far so I can see if you're doing it right.
Then I'll show you how to make a copy constructor for a class with a vector.
Oct 6, 2016 at 4:56pm
Awesome! But the assignment operator, you can show that one aswell? I believe that one feels like the hardest to understand in this case (cause I feel it has no purpose, the default assignment operator works just fine, as you mentioned earlier, it didn't leak memory?).

My main (played around with it);
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
#include <iostream>
#include "vectorh.h"

using namespace std;




int main ()
{

int v_size;

vectorOfInt v1(-5);
v1.pushback(3);
v1.pushback(7);

vectorOfInt v2(4);
v2.pushback(70);
v2.pushback(80);
v2.pushback(90);
v2.pushback(100);
v2.pushback(110);

v1.printVector();
v1 = v2;

}


vectorh.h
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
#ifndef VECTORH_H_INCLUDED
#define VECTORH_H_INCLUDED

class vectorOfInt{
private:
int v_size;
int *p_vector;
void loopThrough();
public:
    vectorOfInt();
    vectorOfInt(int Size);
    ~vectorOfInt();
   // vectorOfInt &operator=(vectorOfInt& rhs);
   // vectorOfInt (vectorOfInt& rhs);


    int getValue(int index);
    void setValue(int index, int  value);
    int setv_size(int option = 0);
    void pushback(int value);
    void pushfront(int value);
    void printVector();
    void coutsize();


};

#endif // VECTORH_H_INCLUDED 


.cpp
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
#include <iostream>
#include "vectorh.h"
using namespace std;



void loopAddZero(int *&p_vector, int v_size, int i = 0){
for (i; i<v_size; ++i){
    if (p_vector[i] != 0){
        p_vector[i] = 0;
    }
}
}



void resizeVector(vectorOfInt &obj, int *&p_vector, int method){
int v_size;
int old_v_size;
int i = 0;

if (method == 1){
    v_size = obj.setv_size();
    old_v_size = v_size/2;
    int *tmp = new int[v_size];

    for (i; i<v_size; ++i){
        tmp[i] = p_vector[i];
    }
    delete [] p_vector;
    loopAddZero(tmp, v_size, old_v_size);
    p_vector = tmp;
}

else if (method == 2){
    v_size = obj.setv_size(1);
    int *tmp = new int[v_size];

    for (i; i<v_size; ++i){
        tmp[i+1] = p_vector[i];
    }
    tmp[0] = 0;
    delete [] p_vector;
    p_vector = tmp;
}
}



int vectorOfInt::setv_size(int option){

if (option == 0){
v_size *= 2;
}
else if (option == 1){
v_size += 1;
}
return v_size;
}



vectorOfInt::vectorOfInt(){
v_size = 32;
p_vector = new int[v_size];
loopAddZero(p_vector, v_size);
}



vectorOfInt::vectorOfInt(int Size){
if (Size <= 0){
    v_size = 1;
    p_vector = new int [v_size];
    loopAddZero(p_vector, v_size);
}
else{
    v_size = Size;
    p_vector = new int [v_size];
    loopAddZero(p_vector, v_size);
}
}



vectorOfInt::~vectorOfInt(){
delete [] p_vector;
}



int vectorOfInt::getValue(int index){
if (index >= 0 && index <v_size){
for (int i = 0; i<v_size; ++i){
    if (index == i){
    return p_vector[index];
    }
}
}
else
return -1;
}



void vectorOfInt::setValue(int index, int value){

if (index >= 0 && index < v_size){
    p_vector[index] = value;
}
return;
}



void vectorOfInt::pushback(int value){
int tmp = 0;

if ((v_size == 1) && (p_vector[0] == 0)){
    p_vector[0] = value;
    return;
}

for (int i = 0; i<v_size; ++i){
if (p_vector[i] != 0){
    tmp = i;
}
}

if (tmp != 0 && tmp+1 < v_size){
    p_vector[tmp+1] = value;
}

else{
    resizeVector(*this,p_vector,1);
    p_vector[tmp+1] = value;
}
}



void vectorOfInt::pushfront(int value){
if (v_size == 1 && p_vector[0] == 0){
    p_vector[0] = value;
    return;
}
else{
resizeVector(*this,p_vector,2);
p_vector[0] = value;
}
}



void vectorOfInt::printVector(){
    int k = 0;
for (int i = 0; i<v_size; ++i){
        if (p_vector[i] != 0){
        cout << "V(" << k << ") = " << p_vector[i] << endl;
        ++k;
        }
    }
}

void vectorOfInt::coutsize(){
cout << v_size;
}
Last edited on Oct 6, 2016 at 5:53pm
Topic archived. No new replies allowed.