Shallow and Deep copy constructors

Hi, I'm having trouble writing a shallow and deep constructor for 2 arrays that demonstrate the differences between shallow and deep copies.

I think I have the deep constructor written ok, but I can't figure out how to write the shallow one.

When I run the program, I don't see a difference between the 2.

Could someone take a look and let me know if it's ok?

The full program is at the bottom.

Here is my code so far for each constructor:



Shallow:

1
2
3
4
5
6
7
WrapArrayShallow(const WrapArrayShallow& was);

//copy constructor
WrapArrayShallow::WrapArrayShallow(const WrapArrayShallow& was)
{
	for (int i = 0; i < 5; i++) pch[i] = was.pch[i];
}


Deep:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
WrapArrayDeep(const WrapArrayDeep &wad);
WrapArrayDeep & operator =(const WrapArrayDeep &wad);


//Copy constructor
//WrapArrayDeep(const WrapArrayDeep &wad);
WrapArrayDeep::WrapArrayDeep(const WrapArrayDeep &wad)
{
	pch = new char[5];

	for (int i = 0; i < 5; i++)
		pch[i] = wad.pch[i];
}


WrapArrayDeep & WrapArrayDeep::operator=(const WrapArrayDeep &wad)
{
	if (this != &wad)
	{
		for (int i = 0; i < 5; i++)
			pch[i] = wad.pch[i];
	}
	return (*this);
}



Full code:

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
#pragma warning(disable: 4996)
#include <cstdlib>
#include <iostream>
#include <string>
#include <cctype>
#include <stack>
#include <conio.h>

using namespace std;

class WrapArrayShallow {
private:
	char *pch;

public:
	WrapArrayShallow();
	void displayWrapArrayShallow();
	void setWrapArrayShallow(char a, char b, char c, char d, char e);
	WrapArrayShallow(const WrapArrayShallow& was);
	WrapArrayShallow & operator = (const WrapArrayShallow& was);
	~WrapArrayShallow();

};

class WrapArrayDeep {
private:
	char *pch;

public:
	WrapArrayDeep();
	void setWrapArrayDeep(int a, int b, int c, int d, int e);
	//Test(const Test &t)
	WrapArrayDeep(const WrapArrayDeep &wad);
	WrapArrayDeep & operator =(const WrapArrayDeep &wad);
	void displayWrapArrayDeep();
	~WrapArrayDeep();
};

//main
int main()
{

	cout << "This program section uses 3 variables.\n";
	cout << "i = 7, pi as a pointer to i, and ppi as a pointer to pi. \n\n";

	int i = 7;
	int *pi = &i;
	int **ppi = &pi;

	cout << "pi = " << pi << "\n";
	cout << "dereference pi " << *pi << "\n";
	cout << "address of pi " << &pi << "\n";
	cout << "address of i " << pi << "\n";
	
	cout << "\n\n";

	cout << "ppi = " << ppi << "\n";
	cout << "dereference of ppi " << *ppi << "\n";
	cout << "address of ppi " << &ppi << "\n";
	cout << "double dereference of ppi " << **ppi << "\n";

	cout << "\n\n";

	cout << "This section instantiates a wrapper class for a dynamic array of 5 elements.\n";

	cout << "\n\n";

	//WrapArrayDeep Section
	WrapArrayDeep wad1;
	WrapArrayDeep wad2;

	cout << "WrapArrayDeep 1 \n";
	wad1.displayWrapArrayDeep();

	cout << "WrapArrayDeep 2 created using the copy constructor on 1\n";
	wad2.displayWrapArrayDeep();

	cout << "After  changing the contents of WrapArrayDeep 1, 1 and 3 = \n";
	wad1.displayWrapArrayDeep();
	wad1.setWrapArrayDeep(102, 103, 104, 105, 106);
	wad1.displayWrapArrayDeep();


	//WrapArrayShallow Section
	WrapArrayShallow was1;
	WrapArrayShallow was2;

	cout << "Now doing the same thing with WrapArrayShallow:\n\n";

	cout << "WrapArrayShallow 1:\n";
	was1.displayWrapArrayShallow();

	cout << "WrapArrayShallow 2 created using the copy constructor on 1:\n";
	was2.displayWrapArrayShallow();

	cout << "After changing the contents of WrapArrayShallow 1, 1 and 3 = \n";
	was1.displayWrapArrayShallow();
	was1.setWrapArrayShallow('f', 'g', 'h', 'i', 'j');
	was1.displayWrapArrayShallow();

	//destructors

	cout << "\n\n";

	was1.~WrapArrayShallow();
	was2.~WrapArrayShallow();

	wad1.~WrapArrayDeep();
	wad2.~WrapArrayDeep();


	//need this so the DOS window doesn't close
	cout << "\n\n";
	system("pause");
	return 0;
}

//Class definitions

//Use array notation to load array
WrapArrayShallow::WrapArrayShallow()
{
	pch = new char[5];
	pch[0] = 'a';
	pch[1] = 'b';
	pch[2] = 'c';
	pch[3] = 'd';
	pch[4] = 'e';

}

//copy constructor
WrapArrayShallow::WrapArrayShallow(const WrapArrayShallow& was)
{
	for (int i = 0; i < 5; i++) pch[i] = was.pch[i];
}

//Use pointer arithmetic to print array
void WrapArrayShallow::displayWrapArrayShallow()
{
	for (int i = 0; i < 5; i++)
		cout << *(pch+i) << " ";
	cout << "\n\n";
}

//Use array notation to set array
void WrapArrayShallow::setWrapArrayShallow(char a, char b, char c, char d, char e)
{
	pch = new char[5];
	pch[0] = a;
	pch[1] = b;
	pch[2] = c;
	pch[3] = d;
	pch[4] = e;
}

//destructor for WrapArrayShallow
WrapArrayShallow::~WrapArrayShallow()
{
	cout << "Calling destructor for WrapArrayShallow!\n";
	delete[] pch;
}

//Use pointer arithmetric to load array with ASCII values for letters
WrapArrayDeep::WrapArrayDeep()
{
	pch = new char[5];
	//use pointer arithmetic to set array values
	*pch = 97;
	*(pch + 1) = 98;
	*(pch + 2) = 99;
	*(pch + 3) = 100;
	*(pch + 4) = 101;
}

//void setWrapArrayDeep(int a, int b, int c, int d, int e);

//use pointer arithmetric to set array values
void WrapArrayDeep::setWrapArrayDeep(int a, int b, int c, int d, int e)
{
	pch = new char[5];
	//use pointer arithmetic to set array values
	*pch = a;
	*(pch + 1) = b;
	*(pch + 2) = c;
	*(pch + 3) = d;
	*(pch + 4) = e;
}

//Copy constructor
//WrapArrayDeep(const WrapArrayDeep &wad);
WrapArrayDeep::WrapArrayDeep(const WrapArrayDeep &wad)
{
	pch = new char[5];

	for (int i = 0; i < 5; i++)
		pch[i] = wad.pch[i];
}

//WrapArrayDeep & operator =(const WrapArrayDeep &wad);
WrapArrayDeep & WrapArrayDeep::operator=(const WrapArrayDeep &wad)
{
	if (this != &wad)
	{
		for (int i = 0; i < 5; i++)
			pch[i] = wad.pch[i];
	}
	return (*this);
}

//Use array notiation to display array
//void displayWrapArrayDeep(const WrapArrayDeep &wad);
void WrapArrayDeep::displayWrapArrayDeep()
{
	for (int i = 0; i < 5; i++)
		cout << pch[i] << " ";
	cout << "\n\n";
}

//destructor for WrapArrayDeep
WrapArrayDeep::~WrapArrayDeep()
{
	cout << "Calling destructor for WrapArrayDeep!\n";
	delete[] pch;
}

Last edited on
> When I run the program, I don't see a difference between the 2.
you never invoke any copy constructor or assignment operator.


> I can't figure out how to write the shallow one.
Then review the theory to understand what is shallow copy.
You shouldn't need to write anything.


> was1.~WrapArrayShallow();
destructors are called automatically when a variable goes out of scope.
If you make an explicit call, then it would be executed twice. So you'll delete your array twice, invoking undefined behaviour.
Shallow/Deep copy in C++? Isn't that a Lisp notion?

I didn't think it applied to C++, but I suppose it could if you reference counted the thing being pointed to.

I think ne555 has covered it. Lecturers these days ...
oh, stupid of me.

disregard what I said about shallow copy, you probably want an implementation that does work (that it does not invoke undefined behaviour or leak resources).
You will copy the pointers this->pch = was.pch; but need to establish a mechanism to decide who would delete the array (because there can be only one delete).

As kbw said, you could implement reference counting, like http://ootips.org/yonat/4dev/counted_ptr.h

There are other possibilities, like transfer ownership or let the creator to manage it.
ne555, actually I need the shallow copy to fail...that is our assignment. The deep copy should be correct and the shallow copy should fail.

So I assume you mean to just not implement a shallow copy constructor?

thanks
The copy constructor and assignment operator would simply copy (or assign) each member. The pointers would point to the same memory address, making a shallow copy.
So you don't need to code them.


In order to test the differences do something like
1
2
3
4
5
6
7
8
foo a;
foo b(a); //shallow copy
foo c;
c = a; //assignment operator
a.set(/**/); //modify 'a'

b.display(); //'b' changed
c.display(); //'c' changed 
Oh ok, so if I wanted to manually assign each member of the original array to a new array, I'd simpy do something like this to create a shallow copy?

1
2
3
4
5
6
7
8
9
10
11
12
myOriginalArray = new char[5];

myOriginalArray[0] = 'a';
myOriginalArray[1] = 'b';
myOriginalArray[2] = 'c';
myOriginalArray[3] = 'd';
myOriginalArray[4] = 'e';

    myShallowCopyArray = new char[5];
 //shallow copy
 for (int i = 0; i < 10; i++)
     myShallowCopyArray[i] = myOriginalArray[i];
No, that would be a deep copy
You would simply do myShallowCopyArray = myOriginalArray;

Then you can observe that if you do myOriginalArray[2] = 'z'; you'll see the change in `myShallowCopyArray'
Topic archived. No new replies allowed.