Page 1
1
Lecture #3• A Quick Review of Pointers• Dynamic Memory Allocation• The “this” pointer!
• Resource Management Part 1– Copy Constructors
Note: We’re only reviewing about 50% of the key pointer concepts!
If you feel uncomfortable with pointers, then study and become an expert before our next class!
Page 2
2
Let’s Play….
Programming Language Inventor
Or
Serial Killer
See if you can guess who uses a keyboard and who uses a chainsaw!
Page 3
3 Every Variable has an Address
You can think of the computer’s memory like a street with a bunch of vacant lots.
Some variables occupy a single lot, while others occupy several adjacent lots.
100 101 102 103 104
MEMORY
void foo(){ short students = 5; char grade = ‘B’;...
students
5
grade
‘B’
When you define a variable in your program, the computer finds an unused
address in memory and reserves it for your variable.
Page 4
4
Variable Addresses
Important: The address of a variable is defined to be the lowest address in memory where the variable is stored.
…
…
0000000000000001
000010000000100100001002000010030000100400001005000010060000100700001008000010090000101000001011
999999909999999199999992
So, what is age’s address in memory?
age
41
grade 66
What about grade’s address?
void foo(){ int age = 41; char grade = ‘A’;...
Page 5
5
We can get the address of a variable using the & operator.
Getting the Address of a Variable
010000100101002010030100401005010060100701008010090101001011
age
41
grade ‘B’
int main(){ int age = 41; char grade = ‘B’;
cout << “age’s address: “<< &age ; cout << “grade’s address: “ << &grade ;}
If you place an & before a variable in a program statement, it means “give me the numerical address of
the variable.”
Output:age’s address: 1006grade’s address: 1011
MEMORY
Page 6
6
Ok, So What’s a Pointer?
chickens
p
...0000100000001002000010040000100600001008000010100000101200001014
...
MEMORY
int foo(){
int chickens;
chickens = 5;
5
I’m a regular variable… and I hold a regular
value!
pointer p;
p = &chickens;
I’m a pointer variable… and all I can hold are the
addresses of other variables!
1000For instance, right
now I hold a value of 1000, the
address of the “chickens” variable.
A pointer variable is a special kind of variable that holds another variable’s
address instead of a regular value.
Regular variables (like floats and ints) just hold simple values like 3.14159 or
42.
Another way to say this is:
“p points to address 1000”
Page 7
7
int foo(){
int chickens;
chickens = 5;
p = &chickens;
Defining a Pointer VariableActually… This isn’t the correct way
to define a pointer variable.
When you define a pointer variable, you have to tell C++ what type of variable it’s going to point to.
int
Oh, and in C++, you use the *
symbol instead of the word “pointer”:
pointer p; * p;
Now we know the proper syntax to define a pointer
variable!
I’d like p to hold the address of (point to)
the chickens variable.
And chickens is an int
variable…So this now tells C++ that the p pointer variable will be used
to point at int variables.
To understand the type of your new variable, simply read your declaration from
right to left…
“Variable p is a pointer to
an int variable.”
Page 8
8
Why do we have to tell C++ what type of variable our pointer points to? Who cares?
Why Specify the Type?
int foo(){
int chickens;
chickens = 5;
p = &chickens;
int *p;
Why the heck do we need
this?
Well, would you tell your veterinarian what kind of pet you had before he performed surgery?
Of course you would – you have to know *what* type of thing you’re pointing at before you can operate on it!
?
Page 9
9
Back to Memory LaneSo in our computer’s memory, we store variables.
MEMORY
1000 1001 1002 1003
But they’re all just variables!
And some variables hold regular values (like ints).
While other variables hold address values.
int foo(){
short chickens = 5;
chickens 5
short *ptr = &chickens;
ptr1001
1004 1005 1006 1007
Finally, every variable in memory has an address!
cout << chickens;cout << ptr;
cout << &chickens;cout << &ptr;
Cool huh?// prints 5// prints 1001
// prints 1001// prints 1004
Page 10
10
What do I do with Pointers?
Answer: You can use your pointer and the star operator to
read/write the other variable.
int main(void){ int var = 1234;
int *ptr;
ptr = &var;
0000100000001002000010040000100600001008000010100000101200001014
...
var
ptr1002
*ptr = 5;
If placed in front of a pointer, the * operator allows us to read/write the variable pointed-to by the pointer.
Question: So I have a pointer variable that points to another
variable… now what?
1234
cout << *ptr;
“Get the address value stored in the ptr
variable…
Then go to that address in memory…
and give me the value stored there.”
1002;Neat! The pointer lets us
indirectly access a value in memory without referring
to its variable name!
I just changed var’s value to
5…
1234;
…without ever referring to its variable name!
// cout << *ptr cout << *1002 cout << 1234
1002
1002
1234“Get the address value stored in the ptr
variable…
Then go to that address in memory…
and store a value of 5 there.”
1002
5 // *ptr = 5 *1002 = 5
Page 11
11
void set(int *pa) { *pa = 5;} int main(){ int x = 1; set(&x); cout << x;}
…
0000000000000001
0000924000009241000092420000924300009244000092450000924600009247000092480000924900009250
x 1
pa 9240
5
Another Pointer Example
9240
Cool – that works! We can use pointers to modify variables from other
functions!
Let’s use pointers to modify a variable inside of another
function.
// prints 5
“Store a value of 5 at location .”
9240
Page 12
12
void set(int *pa) { *pa = 5;} int main(){ int x = 1; set(&x); cout << x;}
What if We Didn’t Use Pointers?
Now what would happen if we didn’t use pointers in our
code?
…
0000000000000001
0000924000009241000092420000924300009244000092450000924600009247000092480000924900009250
x 11
pa 1 5Oh no! We tried to change the value of x
in set but it only changed the local variable!
Had we used a pointer, it would have worked!
// prints 1
Page 13
13
…
0000000000000001
0000924000009241000092420000924300009244000092450000924600009247000092480000924900009250
When you pass a variable by reference to a function, what really
happens?
Pointers vs References
void set(int &val) // val is a ref { val = 5;}
int main(){ int x = 1;
set(x); cout << x;}
In fact, a reference is just a simpler notation for passing by a pointer!
x
It looks like we’re just passing the value of x,
but in fact…
Since the set function accepts a reference…
This line is really passing the address of
variable x to set…
9240
(Under the hood, C++ uses a pointer)
val 9240
Since val points to our original variable, x,
this line actually changes x!
5
1
Page 14
14
Your "nature" pictures?Operating system??
What Happens Here?int main(){ int *iptr;
…
0000000000000001
0000924000009241000092420000924300009244000092450000924600009247000092480000924900009250
iptr
What address does iptr hold?
?????
Who knows??? Since the programmer didn’t initialize it, it points to some
random spot in memory!
CRASH!
Moral: You must always set the value
of a pointer variable before using the * operator on it!
*iptr = 123456; // #1 mistake!}
int someVar;iptr = &someVar; // now iptr is valid!
// A-OK now!
123456
Page 15
15
Class ChallengeWrite a function called swap that accepts twopointers to integers and swaps the two values
pointed to by the pointers.
int main(void){ int a=5, b=6;
swap(&a, &b); cout << a; // prints 6; cout << b; // prints 5}
Prize: 3 prize tickets (and maybe some
candy)
Hint: Make sure you never use a pointer
unless you point it to a variable first!!!
Page 16
16
Class Challenge Solution
void swap (int *pa, int *pb){ int temp; temp = *pa; *pa = *pb; *pb = temp;}
int main(){ int a=5, b=6; swap(&a,&b); cout << a; cout << b;}
…
0000000000000001
0000924000009242000092440000924600009248000092500000925200009254000092560000925800009260
a 5
b 69240, 92449240 9244
pa 9240
pb 9244
temp -23
Get the value stored at location
9240…and put it in temp.
5
Get the value stored at
location 9244…
And put it into location
9240.
6
Get the value stored in temp and store it in
location 9244…
Page 17
17
Wrong Challenge Solution #1
void swap (int *pa, int *pb){ int *temp; *temp = *pa; *pa = *pb; *pb = temp;}
int main(){ int a=5, b=6; swap(&a,&b); cout << a; cout << b;}
…
0000000000000001
0000924000009242000092440000924600009248000092500000925200009254000092560000925800009260
a 5
b 69240, 92449240 9244
pa 9240
pb 9244
temp 50000
Get the value stored at
location 9240…
And put it in location
50000!
5
CRASH!
Problem: In this solution,we use a pointer without first
pointing it at a variable!
Page 18
18
Wrong Challenge Solution #2
void swap (int *pa, int *pb){ int *temp; temp = pa; pa = pb; pb = temp;}
int main(){ int a=5, b=6; swap(&a,&b); cout << a; cout << b;}
…
0000000000000001
0000924000009242000092440000924600009248000092500000925200009254000092560000925800009260
a 5
b 69240, 92449240 9244
pa 9240
pb 9244
temp 50000
9240
9244
9240
// prints 5// prints 6
Problem: In this solution,we swap the pointers but not
the values they point to!
Page 19
19
Arrays, Addresses and Pointers
int main(){ int nums[3] = {10,20,30};
}
Just like any other variable, every array has an address in memory and you can get it with the & operator.
…0000924000009242000092440000924600009248000092500000925200009254000092560000925800009260
10
20
30
nums
[0]
[1]
[2]
cout << &nums;// prints 9242
But… in C++ you don’t even need to use the & operator to
get an array’s address!
cout << nums;// also prints 9242
You can simply write the array’s name (without brackets) and C++ will give you the array’s
address! 92429242
And here’s how to make a pointer point to an array…
int *ptr = nums; // pointer to array
ptr
9242
Question: So is “nums” an address or a pointer or what?
Answer: “nums” is just an array. But C++ lets you get its address
without using the & so it looks like a pointer…
ptr is a pointer variable.
Why? Because it’s a variable that holds an
address value!
nums is just an array.
It holds three regular integer values.
But it doesn’t hold an address like a pointer variable, so it’s not a
pointer!
Page 20
20
Arrays, Addresses and Pointers
int main(){ int nums[3] = {10,20,30};
}
In C++, a pointer to an array can be used just as if it were an array itself!
…0000924000009242000092440000924600009248000092500000925200009254000092560000925800009260
10
20
30
nums
[0]
[1]
[2]int *ptr = nums; // pointer to array
ptr
cout << ptr[2];
9242
// prints nums[2] or 30
Or you can use the * operator with your pointer to access the
array’s contents.
cout << *ptr; // prints nums[0] or 10
cout << *(ptr+2); // prints nums[2] or 30
Since ptr points to the top of the nums array,
this prints out the value that is two
integer elements from the top of the nums
array.
Since ptr points to the top of the nums array, this
prints out the value that is at address 9242 – i.e., the first element of the nums
array.
This line says “print out the item that is two elements down from where ptr points.” (in this
case, ptr points to the top of the array)
It’s the same as printing out nums[2] or ptr[2].
In C++, the two syntaxes have identical behavior:
ptr[j] *(ptr + j)
They both mean: “Go to the address in ptr, then skip down j elements and get the value.”
They both mean: “Go to the address in ptr, then skip down j elements and get the value.”
They both mean: “Go to the address in ptr, then skip down j elements and get the value.”
NOTE: when we say “skip down j elements,” we don’t just mean “skip
down j bytes!”
Instead we mean, skip over j of the actual elements/values in the array
(e.g., skip over the values 10 and 20 to get to 30)
Page 21
21
array
Pointer Arithmetic and Arrays
void printData(int array[ ]){ cout << array[0] << “\n”; cout << array[1] << “\n”;}int main(){ int nums[3] = {10,20,30};
printData(nums);
printData(&nums[1]);
printData(nums+1);}
Did you know that when you pass an array to a function…
You’re really just passing the address to the start of the
array!… not the array itself!
nums[0]
[1]
[2]
10
20
30
3000
3004
3008
3000
int *array
array
This line prints the element that is zero items
from the top of where ‘array’ points to.
This line prints the element that is one item from the top.
Since array starts at 3000, and each item is an integer, our next integer is at 3004…
10
20
Here we’re passing the address of the second element of the array.
Since nums[0] is at address 3000, nums[1] one is 4 bytes down at
3004.3004
The array parameter variable is actually a
pointer!
You can use [ ] syntax if you like but it’s REALLY a
pointer!
Page 22
22
array
Pointer Arithmetic and Arrays
void printData(int array[ ]){ cout << array[0] << “\n”; cout << array[1] << “\n”;}int main(){ int nums[3] = {10,20,30};
printData(nums);
printData(&nums[1]);
printData(nums+1);}
Did you know that when you pass an array to a function…
You’re really just passing the address to the start of the
array!… not the array itself!
nums[0]
[1]
[2]
10
20
30
3000
3004
3008
3004
array
Our printData function thinks the array actually starts at location 3004!
It knows nothing about the earlier part of the array!
This prints the element that’s zero items from the top of where our array
starts…
i.e., the item at location 3004!
1020
[0]
[1]
20
and this prints the item that is one item down from the start of the array…
If the array starts at 3004, then the next integer is in slot 3008!
30
3000
When you use recursion on arrays,
you’ll often use this notation…
To process successively smaller suffixes of the array.
This line is tricky!
First, what happens when you just write the name of an array all by
itself?
Answer: C++ replaces the name with the start address of the array.
Ok. But what happens when we add 1 to the address? Do we get a value of 3001?
Let’s say you’re at 3000 Gayley and you ask “What’s the address of the next
building?”
Well, it’s probably not 3001. It’s probably something like 3010, right?
Similarly, if you’re at address 3000 and you ask for the address of the array
element that’s one slot down, the next element isn’t at 3001… in this case, it’s
at 3004!
+ one array element down
So this statement:
nums + 1
is really saying
“Advance one element (one integer) down
from the start of the nums array.”
3004
Page 23
23
Pointers Work with Structures Too!
struct Nerd{int numZits;int hoursOfStarCraft;
};
int main(){ Nerd carey; Nerd *ptr;
ptr = &carey;
(*ptr).numZits = 140;
}
000010000000100100001002000010030000100400001005000010060000100700001008000010090000101000001011000010120000101300001014000010150000101600001017
carey
.numZits
.hoursOfStarCraft
140
42
1000ptr
Or you can use C++’s -> operator to access fields!
ptr->hoursOfStarCraft = 42;
You can use pointers to access structs too! Use the * to get to the structure,
and the dot to access its fields.
Page 24
2530003001300230033004300530063007300830093010
…
class Circ{public: Circ(float x, float y, float rad) { m_x = x; m_y = y; m_rad = rad; }
float getArea(void) { return (3.14 * m_rad * m_rad); }
…
private: float m_x, m_y, m_rad;};
void printInfo(Circ *ptr){ cout << “The area is: “; cout << ptr->getArea();}
int main(){ Circ foo(3,4,10);
printInfo(&foo);}
Classes and Pointers
You can use pointers with classes just like you do with
structs.
class Circ{public: Circ(float x, float y, float rad) { m_x = x; m_y = y; m_rad = rad; }
float getArea(void) { return (3.14 * m_rad * m_rad); }
…
private: m_x m_y m_rad};
foo
3 4 10
3000
3 4 10
ptr 3000
The area is:
C++: Since ptr points to 3000, I’ll call the
getArea function associated with the
foo variable at 3000!
1010
314
(*ptr).getArea();
You can also use this alternate syntax…
(It does the same thing)
Page 25
26
And now it’s time for your favorite game!
Page 26
27
A New Type of VariableThus far, all variables we’ve defined have either been
local variables,
void foo(void){ int a; cin >> a;}
int aGlobalVariable;
int main(){ Circ a(3,4,10); float c[10];
c[0] = a.getArea();}
or class member variables.
class Student{public: string getZits(void) { int numZits = m_age * 5; return(numZits); }private: string m_name; int m_age;};
global variables
Let’s learn about a new type of variable: a dynamic variable
Page 27
28
Dynamic VariablesYou can think of traditional variables like rooms in your
house.Just like a room can hold a person, a variable holds a
value.
But what if you run out of rooms because all of your aunts and uncles surprise
you and come over.
In this case, you have to call a hotel, reserve some rooms, and place your relatives in the hotel
rooms instead.
?
?
Page 28
29
Dynamic VariablesIn a similar fashion, sometimes
you won’t know how many variables you’ll need until your
program runs.In this case, you can
dynamically ask the operating system to reserve new memory
for variables.The operating system will allocate room for
your variable in the computer’s free memory and then return the address of the new
variable.When you’re done with the variable, you can tell
the operating system to free the space it occupies for someone else to use.
Page 29
30
New and DeleteFor example, let’s say we want to define an array, but we won’t know how big to make it until our program actually
runs …
int main(void){ int *arr; int size; cin >> size;
arr = new int[size];
arr[0] = 10; arr[2] = 75;
delete [] arr;}
The new command can be used to allocate an arbitrary amount of memory
for an array. How do you use it?
1. First, define a new pointer variable.2. Then determine the size of the array you need.
3. Then use the new command to reserve the memory. Your pointer gets the address of the memory.
4. Now just use the pointer just like it’s an array!
5. Free the memory when you’re done (check your relatives out of the hotel).
#1
#2
#3
#4
#5
Note: Don’t forget to include brackets
delete [ ] ptr;
if you’re deleting an array…
Your pointer variable will then be assigned the
address of the new array.
So it points to the new array!
Page 30
31
New and Delete
int main(void){ int size, *arr; cout << “how big? ”; cin >> size;
arr = new int[size];
arr[0] = 10; // etc
delete [] arr;}
The new command requires two pieces of information:
1. What type of array you want to allocate.
2. How many slots you want
in your array.Make sure that the pointer’s
typeis the same as the type of
array you’re creating!
Page 31
32
int main(void){ int *arr; int size;
cin >> size;
arr = new int[size];
arr[0] = 10; // etc
delete [] arr;}
New and Delete…
000010000000100100001002000010030000100400001005000010060000100700001008
…
arr
size
3
3
First, the new command determines how much memory it needs for the
array.
4 * 3 = 12 bytes
Page 32
33
int main(void){ int *arr; int size;
cin >> size;
arr = new int[size];
arr[0] = 10; // etc
delete [] arr;}
New and Delete…
000010000000100100001002000010030000100400001005000010060000100700001008
…
arr
size
3
Next, the new command asks the operating system to reserve that
many bytes of memory.
4 * 3 = 12 bytes
Operating System – can you reserve 12 bytes of
memory for me?
...
0003005000030051000300520003005300030054
...00030060
Ok.. I found 12 bytes of free memory at address
30050.
Page 33
34
int main(void){ int *arr; int size;
cin >> size;
arr = new int[size];
arr[0] = 10; // etc
delete [] arr;}
…000010000000100100001002000010030000100400001005000010060000100700001008
…
arr
size
3
Finally, your pointer variable gets the address of the newly reserved memory.
4 * 3 = 12 bytes
...
0003005000030051000300520003005300030054
...00030060
30050
10
New and Delete
You can also use the * notation if you like (instead of brackets)
*(arr+0) = 10; // arr[0] = 10;*(arr+1) = 20; // arr[1] = 20;
You can now treat your pointer just like an array!
(i.e. use [ ] to index it)
Page 34
35
int main(void){ int *arr; int size;
cin >> size;
arr = new int[size];
arr[0] = 10; // etc
delete [] arr;}
…000010000000100100001002000010030000100400001005000010060000100700001008
…
arr
size
3
...
0003005000030051000300520003005300030054
...00030060
30050
10When you’re done, you use the
delete command to free the array.
Usage: delete [] ptrname;
Ok.. I’ll let someone else use that memory now…
New and Delete
arr[0] = 50; }
… not the pointer variable itself!
Our pointer variable still holds the address of the
previously-reserved memory slots!
Note: When you use the delete command, you
free the pointed-to memory…
But they’re no longer reserved for this program!
So don’t try to access them or bad things will
happen!
Operating System – I’m done with my 12 bytes of
memory at location 30050.
CRASH!
Page 35
36
int main(void){ double *arr; int size;
cin >> size;
arr = new double[size];
// succesfull allocation arr[5] = 12345; arr[7] = 61616; delete [] arr;}
…000010000000100100001002000010030000100400001005000010060000100700001008
…
arr
size 4000000000
4000000000
If the new command fails (i.e. there’s not enough memory), then the new command will
cause your program to CRASH!
8 * 4000000000= 32 billion bytes
Operating System – can I have… uh… err..
32 BILLION bytes of memory?
Ok – well in that case, I’ll just CRASH the
program… HA!
32 BILLION?!!?? ARE YOU SMOKING CRACK? NO WAY!
New and Delete
CRASH!
C++ has a way for the programmer to check for such
errors and address them properly…
But that’s beyond the scope of CS32(So for now, don’t worry about checking for errors in this case)
Page 36
37
class MathProf{public: MathProf() { for (int j=0;j< 100 ;j++) m_arr[j] = j*j;
}
void printSquares() { for (int j=0;j< 100 ;j++) cout << m_arr[j];
}private:
int m_arr[100];};
Using new and delete in a class
Well, here we have a math professor class…
int main(void){ MathProf stupidProf(5); MathProf smartProf(100);
stupidProf.printSquares(); smartProf.printSquares(); }
So how we might use new/delete within a class?
And as you can see, math profs can only memorize up to 100
square #s!Let’s update our class so they can memorize as many #s as
they like!
MathProf(int n) {
Step #1:Change our fixed array to a pointer variable and add a size variable.
Step #2:Update our constructor so the user can pass in the size of the prof’s array.
Step #3:Use the new command to allocate an array of the right size. Remember its size!
m_n
Step #5:Update our loop so we print out all N numbers.
~MathProf() { delete [] m_arr; // free memory}
int *m_arr, m_n;
m_n
m_arr = new int[n]; // alloc arraym_n = n; // store its size!
Step #4:Update our loop so we compute the first n square numbers (instead of just the first 100)
Step #6:Add a destructor that frees the dynamic array when we’re done!
Page 37
38
More New and Delete So we just saw how to use new and delete to allocate arrays…
We can also use new and delete to allocate non-array variables.
Let’s see!
Page 38
39struct Book{ string title; string author;};
class CompSciStudent{public: CompSciStudent(string name) { m_myBook = nullptr; m_myName = name; }
void giveBook(string t, string a) { m_myBook = new Book; m_myBook->title = t; m_myBook->author = a; }
~CompSciStudent() { delete m_myBook; }private: Book *m_myBook; string m_myName;};
As we know, most Comp Sci students
hate to carry around heavy books unless
they absolutely have to.
So if I just define a CS student he won’t
by default have a book… (Nor will he have to reserve thememory required to
hold a book)
int main(void)
{
CompSciStudent s(“Hal”);
...
}
s m_myBook
m_myName
nullptr
“Hal”Operating System, can
you free the memory for me at location nullptr?
OS: There’s no need to. The user never allocated any
memory (I can tell by the nullptr value)
“Hal”
nullptr is a special constant used to indicate an invalid or unused
pointer. This indicates that the m_myBook variable doesn’t hold a valid
address at this time.
Page 39
40struct Book{ string title; string author;};
class CompSciStudent{public: CompSciStudent(string name) { m_myBook = nullptr; m_myName = name; }
void giveBook(string t, string a) { m_myBook = new Book; m_myBook->title = t; m_myBook->author = a; }
~CompSciStudent() { delete m_myBook; }private: Book *m_myBook; string m_myName;};
But what if we have a particularly nerdy
CS student and we’ve given her a book to
hold. Let’s seewhat happens!
int main(void)
{
CompSciStudent s(“Liz”);
s.giveBook("Calc", "Bill Nye");
}
s m_myBook
m_myName
nullptr
“Liz”
OS: Sure thing. Here’s some memory for you at address
45000.
45000
44999 ...
45100 ...
45000
title
author
"Calc"
"Bill Nye"
OS: Sure thing. I’ll free it for someone else to use.
So now you see how we can use dynamic variables to ensure
that we only allocate the minimum amount of memory that our
classes need!
“Liz”
"Calc" "Bill Nye"
Operating System, can you free the memory for me at location 45000?
Operating System, can you allocate enough memory to
hold a Book structure for me?Finally, notice that we don’t
need the [ ] brackets when we delete m_myBook!
This is because we allocated just one book…
not a whole array of them!
Page 40
41 Using new and delete to Allocate Class Variables
So we saw how to use new and delete to allocate a struct
variable. Can we use new and delete to
allocate a class variable which has constructors and/or destructors?Yes!
Let’s see how it works.
Page 41
42
0000400000004002000040040000400600004008
…...
int main(void){ Waldo *ptr; ptr = new Waldo(165);
...
delete ptr;}
000010000000100200001004000010060000100800001010
...
ptrclass Waldo{public: Waldo(int weight) { m_weight = weight; m_bacteria = 0; }
~Waldo() { m_weight = 0; // DEAD! m_bacteria = 1000000; //eww }
private: int m_weight, m_bacteria;};
new/delete With C’tors, D’tors
Part #1: C++ reserves memory for your object
”Hey Operating System, can you reserve enough bytes to hold a Waldo variable for me?”
Sure. I just reserved some memory for you
at address 4000.
Now lets see how new and delete work with classes
containing constructors and destructors!
4000
When you use the new command to allocate a class
with a constructor, C++ uses a two-part process!
.m_weight
.m_bacteria
Page 42
43
Now lets see how new and delete work with classes
containing constructors and destructors!
0000400000004002000040040000400600004008
…
...
ptr 000010000000100200001004000010060000100800001010
...
int main(void){ Waldo *ptr; ptr = new Waldo(165);
...
delete ptr;}
new/delete With C’tors, D’tors
...class Waldo{public: Waldo(int weight) { m_weight = weight; m_bacteria = 0; }
~Waldo() { …
Part #2: C++ calls the class’s constructor to initialize the newly allocated memory
“Now that I’ve allocated enough memory to hold Waldo, I’ll call his constructor to initialize
him!”
165
4000
.m_weight
.m_bacteria165
0
Page 43
44
When you use the delete command to free an object with a destructor, C++ also uses a
two-part process!
int main(void){ Waldo *ptr; ptr = new Waldo(165);
...
delete ptr;}
new/delete With C’tors, D’tors
class Waldo{public: ...
~Waldo() { m_weight = 0; m_bacteria = 1000000; }
0000400000004002000040040000400600004008
…
ptr 000010000000100200001004000010060000100800001010
...
4000
.m_weight
.m_bacteria165
0OK. I’ll free up that
memory for someone else…
Part #1: C++ calls the class’s destructor
“While I still have ownership of Waldo’s memory, I’m going to call
Waldo’s destructor on it.”
Part #2: C++ asks the Operating System to free the memory
“Hey O.S., now that I’ve run Waldo’s destructor, can you free that memory at address 4000 for
me.”
0 1000000
Page 44
45
Using new and delete to Allocate Class Instances
When we use new to allocate a class instance, this is what happens:
1. Memory is allocated by the OS for us.
2. The constructor for the class is called on this memory, to initialize it (if the class has a c’tor).
When you delete a class instance, this is what happens:
1. The destructor for the class is called, first (if the class has a destructor).
2. The memory is released to the OS.
Page 45
Classes and the “this” Pointer
Before C++, in the dark ages when Carey learned programming, we didn’t use classes!
Let’s see how we used to do things… with structs, pointers, and functions instead of classes!
And maybe this will help us understand how C++ classes actually
work!
Page 46
The Old Days…Before Classes
Before C++, we would use structs,
pointers and regular functions
to create class-like programs.
struct Wallet{ int num1s, num5s;};
void Init(Wallet *ptr){ ptr->num1s = 0; ptr->num5s = 0;}
void AddBill(Wallet *ptr, int amt){ if (amt == 1) ptr->num1s++; else if (amt == 5) ptr->num5s++;}
void main(void){ Wallet w; Init(&w);
AddBill(&w , 5);}
4000
4000
wnum1s
num5s
ptr 4000
00
ptr 4000
4000
To let a function operate on a struct variable, we used to have to pass in the variable’s address...
The function can then use its pointer to get
to the original variable.
As it turns out, C++ classes work in an almost identical
fashion!
5
amt 5
A Wallet structure keeps track of how
many $1 and $5 the wallet holds…The Init() function
initializes the wallet...
It’s like a constructor.
And the AddBill() function lets us add a bill to the
wallet...
by updating the contents of the struct.
1
Page 47
class Wallet{public: void Init(); void AddBill(int amt); …
private: int num1s, num5s; };
void Wallet::Init() { num1s = num5s = 0; }void Wallet::AddBill(int amt) { if (amt == 1) num1s++; else if (amt == 5)num5s++;}
The Wallet ClassHere’s a class equivalent of
our old-skool Wallet…
As you can see, we can initialize a new wallet…
And we can add either a $1 or $5 bill to our wallet.
Our wallet then keeps track of how many bills of
each type it holds…
int main(){ Wallet a;
a.Init(); a.AddBill(5); }
And here’s how we might use our class…
Page 48
Every time you call a member function of an object, e.g.:
C++ invisibly rewrites your function call and passes in the variable’s address!
a.addBill(5);
addBill(&a, 5);
And C++ does the same thing to your actual member functions!
int main(){ Wallet a, b;
a.Init(); b.AddBill(5);}
void Wallet::Init() { num1s = num5s = 0; }void Wallet::AddBill(int amt) { if (amt == 1) num1s++; else if (amt == 5)num5s++;}...
int main(){ Wallet a, b;
Init( AddBill( }
);a. & 5);b. & ,
void Init( { num1s = num5s = 0; }void { if (amt == 1) num1s++; else if (amt == 5) num5s++;}...
Wallet )
Wallet int amt)
::
::
*thisInit(Wallet *this)
this-> this->
AddBill(*this,
this->this->
So here we’re calling the Init() method of a… But here’s what’s
REALLY happening!
It adds a hidden first argument that’s a pointer to your original variable!
Here what your Init() method looks like… But here’s what’s
REALLY happening!
Classes and the “this” Pointer
Page 49
int main(){ Wallet a, b;
a.Init(); a.AddBill(5);}
void Wallet::Init() { num1s = num5s = 0; }void Wallet::AddBill(int amt) { if (amt == 1) num1s++; else if (amt == 5)num5s++;}...
int main(){ Wallet a, b;
Init(&a); AddBill(&b,5);}
void Init(Wallet *this) { this->num1s = this->num5s = 0; }void AddBill(Wallet *this, int amt) { if (amt == 1) this->num1s++; else if (amt==5) this->num5s++;}...
C++ converts all of your member functions automatically and invisibly by adding an extra pointer parameter called “this”:
Yes… the pointer is actually called “this”!
Classes and the “this” Pointer
Page 50
int main(){ Wallet a;
a.Init(&a);
a.AddBill(&a , 5); }
void Wallet::Init(Wallet *this) { this-> num1s = this-> num5s = 0; }void Wallet::AddBill(Wallet *this, int amt) { if (amt == 1) this-> num1s++; else if (amt==5) this-> num5s++;}...
1000
a num1s
num5s
1000
this 1000
0
1000
01
This is how it actually works under the hood….
But C++ hides the “this pointer” from you to simplify things.
Classes and the “this” Pointer
5
amt 5
Page 51
int main(){ Wallet a;
a.Init();
}
void Wallet::Init() { num1s = num5s = 0;
}void Wallet::AddBill(int amt) { if (amt == 1) num1s++; else if (amt == 5) num5s++;}...
Your class’s methods can use the this variable to determine
their address in memory!
While C++ hides the “this pointer” from you, if you want, your class’s methods can explicitly use
it.
cout << “I am at address: “ << this;
cout << “a is at address: “ << &a;
a num1s
num5s
100000
I am at address: 1000a is at address: 1000
Classes and the “this” Pointer
this->num1s = this->num5s = 0;
You can explicitly use the “this” variable in your methods if you
like!
It works fine!
So now you know how C++ classes work under the
hood!
Page 52
53
Copy Construction
Last time we saw how to create a
constructor function for a class…
class Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ(int x, int y, int r) { m_x = x; m_y = y; m_rad = r; }
Our simple constructor accepts
three ints as arguments..
Question: Can constructors accept other types of
variables as parameters?Let’s see…
Page 53
54
class Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ(int x, int y, int r) { m_x = x; m_y = y; m_rad = r; }
Copy Construction
For example, what if I have
a Point class like this…
class Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ( ) {
}
If we like, we can define a Circ constructor that
accepts a Point variable as an argument!
class Point // an x,y coordinate{public: int m_x, m_y; };
const Point &ptAnd of course, we still want
our constructor to have a radius parameter…
, int rad
m_x = pt.m_x;m_y = pt.m_y;m_rad = rad;
Finally, we can write our constructor’s body…
Allright, let’s see it in action…
const means that our function
can’t modify the pt variable.
The & means “pass by
reference” which is more efficient.
Page 54
55
class Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ(int x, int y, int r) { m_x = x; m_y = y; m_rad = r; }
Copy Construction
class Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ( ) {
}
class Point // an x,y coordinate{public: int m_x, m_y; };
const Point &pt, int rad
m_x = pt.m_x;m_y = pt.m_y;m_rad = rad;
int main(){ Point p; p.m_x = 7; p.m_y = 9;
Circle c(p,3);
cout << c.getArea(); ...}
p m_xm_y
79
class Circ{ ... Circ(const Point &pt,int rad) { m_x = pt.m_x; m_y = pt.m_y; m_rad = rad; } ...private: m_x m_y m_rad }
c
3
79
3
And now we have a fully constructed
Circle!
Page 55
56
Copy Constructionclass Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ( ) {
}
const Point &pt, int rad
m_x = pt.m_x;m_y = pt.m_y;m_rad = rad;
Circ(int x, int y, int r) { m_x = x; m_y = y; m_rad = r; }
Ok, so we’ve seen a simple
constructor… And a constructor
that accepts another class’s
variable… What if we want to define a
constructor for Circ that accepts another Circ variable??
That makes
my head spin!
int main(){ Circ a(1,2,3);
Circ b(a); ...}
This will allow us to initialize a new Circ
variable (b) based on the value of an existing
Circ variable (a).Let’s see how to do it! Circ( )
{
}
const Circ &old
m_x = old.m_x;m_y = old.m_y;m_rad = old.m_rad;
Page 56
57
Copy Construction
int main(){ Circ a(1,2,3);
Circ b(a); ...}
class Circ{ ... Circ(int x, int y, int rad) { m_x = x; m_y = y; m_rad = rad; } ...private: m_x m_y m_rad }
a
321
1 2 3
class Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ(int x, int y, int r) { m_x = x; m_y = y; m_rad = r; }
Circ( ) {
}
const Circ &old
m_x = old.m_x;m_y = old.m_y;m_rad = old.m_rad;
Circ( ) {
}
const Point &pt, int rad
m_x = pt.m_x;m_y = pt.m_y;m_rad = rad;
class Circ{ ... Circ( const Circ &old ) { m_x = old.m_x; m_y = old.m_y; m_rad = old.m_rad; } ...private: m_x m_y m_rad }
b
But wait! Circ variable b is accessing the private
variables/functions of Circ variable a – isn’t that violating C++ privacy
rules?
1 2 3This means:“Initialize variable b
based on the value of
variable a.”
This kind of thing is actually pretty useful… It lets us
create a new variable with the same value as an
existing variable.
Carey says:
That’s not a problem. Every Circ variable is allowed to “touch” every
other Circ variable’s privates – “private” protects one class from
another, not one variable from another (of the same class)!
So every CSNerd object can touch every other CSNerd object’s
privates.
But a CSNerd can’t touch an EENerd’s privates (for obvious
reasons).
Page 57
58
Copy Construction
int main(){ Circ a(1,2,3);
Circ b(a); ...}
class Circ{public:
float GetArea(void) const;private:float m_x, m_y, m_rad;
};
Circ(int x, int y, int r) { m_x = x; m_y = y; m_rad = r; }
Circ( ) {
}
const Circ &old
m_x = old.m_x;m_y = old.m_y;m_rad = old.m_rad;
Circ( ) {
}
const Point &pt, int rad
m_x = pt.m_x;m_y = pt.m_y;m_rad = rad;
In C++ talk, this function is called a “copy
constructor.”A copy constructor is a constructor function
that is used toinitialize a new variable from an existing variable
of the same type.
Page 58
59
Copy Constructionclass Circ{public:Circ(float x, float y, float r){
m_x = x; m_y = y; m_rad = r;}
float GetArea(void){ return(3.14159*m_rad*m_rad);}
private:float m_x, m_y, m_rad;
};
Circ( const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}
int main(){ Circ a(1,1,5);
Circ b(a);
cout << b.GetArea();}
A Copy Constructor is just like a regular
constructor.
However, it takes another instance of the
same class as a parameter instead of
regular values.
Page 59
60
Copy Constructionclass Circ{public:Circ(float x, float y, float r){
m_x = x; m_y = y; m_rad = r;}
float GetArea(void){ return(3.14159*m_rad*m_rad);}
private:float m_x, m_y, m_rad;
};
Circ( const Circ & oldVar){
m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}
The parameter to your copy
constructor should be const!The parameter to
your copy constructor
must be a reference!The type of your
parameter must be the same type as the
class itself!
This is a promise that you won’t modify the
oldVar while constructing your new variable!
oldVar.m_x = 10; // error ‘cause of const
This one’s a bit more difficult to explain right
now.
For now, just make sure you use an & here!
Page 60
61
Copy Constructionclass Circ{public:Circ(float x, float y, float r){
m_x = x; m_y = y; m_rad = r;}
float GetArea(void){ return(3.14159*m_rad*m_rad);}
private:float m_x, m_y, m_rad;
};
Circ( const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}
Oh, C++ also allows you to use a simpler syntax…
Instead of writing:
Circ b(a);
which is ugly…
You can write:
Circ b = a;
It does exactly the same thing! It defines a new
variable b and then calls the copy constructor!
int main(){ Circ a(1,2,3);
Circ b(a);} Circ b = a; // same!
Page 61
62
Copy Constructionclass Circ{public:Circ(float x, float y, float r){
m_x = x; m_y = y; m_rad = r;}
float GetArea(void){ return(3.14159*m_rad*m_rad);}
private:float m_x, m_y, m_rad;
};
Circ( const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}
The copy constructor is not just used when you initialize a new variable from an existing one:
Circ b(a);
It’s used any time you make a new copy of an existing class variable.
Can anyone think of other times when a copy
constructor would be used?
Page 62
63
Copy Constructionvoid foo(Circ temp){ cout << “Area is: “ << temp.GetArea();}
int main(){ Circ a(1,2,10);
foo(a);}
class Circ{public:Circ(float x, float y, float r){
m_x = x; m_y = y; m_rad = r;}
float GetArea(void){ return(3.14159*m_rad*m_rad);}
private:float m_x, m_y, m_rad;
};
Circ( const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}
Here’s a simple program that passes a circle to a
function…
Any guesses if/when the copy constructor is
called?
class Circ{ ... Circ(int x, int y, int rad) { m_x = x; m_y = y; m_rad = rad; } ...private: m_x m_y m_rad }
a
1 2 10
Wait a second!
We’re creating a new variable called temp and copying the value of a into it! Hmmm!!!
class Circ{ ... Circ(const Circ &old) { m_x = old.m_x; m_y = old.m_y; m_rad = old.m_rad; } ...private: m_x m_y m_rad }
temp
1 2 10
Now our temp variable has been copy-constructed, it can be used normally by our foo
function!
Page 63
64
Copy Constructionclass Circ{public:Circ(float x, float y, float r){
m_x = x; m_y = y; m_rad = r;}
float GetArea(void){ return(3.14159*m_rad*m_rad);}
private:float m_x, m_y, m_rad;
};
Circ(const Circ & oldVar){ m_x = oldVar.m_x; m_y = oldVar.m_y; m_rad = oldVar.m_rad;}
If you don’t define your own copy constructor…
C++ will provide a default one for you…
It just copies all of the member variables
from the old instance to the new instance…
int main(){ Circ a(1,2,3);
Circ b(a);}
a m_xm_y
m_rad
123
b m_xm_y
m_rad
123
But then why would I ever need to define my own copy constructor?
Carey says:
“Patience, grasshopper! I’ll show
you in a minute!”
Page 64
65
Copy Construction
Well, we’ll see very soon.
But first, I want to show you a new class called
Squares…
Ok – so why would we ever need to write our own Copy Constructor function?
After all, C++ copies all of the member variables for us automatically if we don’t
write our own!
Page 65
66
Copy ConstructionLet’s consider another class for a second…
class Squares{public: Squares(int n) { m_n = n; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~Squares() { }
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int m_sq[5], m_n;};
The Squares class can be used to compute the first n square numbers.
When you construct it, it fills in the array with each square number.
You can then call the printSquares function to print out the numbers.
Page 66
67
Copy ConstructionLet’s consider another class for a second…
class Squares{public: Squares(int n) { m_n = n; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~Squares() { }
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int m_sq[5], m_n;};
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
a m_n
m_sq
3
31 4 9
In this example, we initialize b to be the same
as a.
Page 67
68
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
Copy Construction
class Squares{public: Squares(int n) { m_n = n; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~Squares() { }
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int m_sq[5], m_n;};
When you init b from a, C++ copies the value of every member
variable from variable a to variable b.
b m_n
m_sq
31 4
a m_n
m_sq
31 4 9
This is called a “shallow copy.” a and b now contain identical
member values.
9
Let’s consider another class for a second…
Page 68
69
Copy Construction
class Squares{public: Squares(int n) { m_n = n; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~Squares() { }
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int m_sq[5], m_n;};
This is exactly what you’d want to happen, right?
a m_n
m_sq
31 4
b m_n
m_sq
31 4 9
1 4 9
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
// b’s d’tor called
149
Let’s consider another class for a second…
Page 69
70
class Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~ Squares(){delete []m_sq;}
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int *m_sq, m_n;};
Copy Construction
Now let’s look at an updated version of our
Squares class.
It uses new and delete to dynamically allocate memory for its array.
When constructed, it uses new to dynamically
allocate an array to hold its square numbers.
And when it is destructed, it uses
delete to release this array.
Let’s see what happens with this class.
Page 70
71
Copy Construction
class Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~ Squares(){delete []m_sq;}
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int *m_sq, m_n;};
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
3
a m_n
m_sq
3
Operating system, can you reserve 12 bytes of memory for
me?
000008000000080400000808Sure, I’ll reserve
12 bytes for you at address 800.
800
149
Page 71
72
Copy Construction
class Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~ Squares(){delete []m_sq;}
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int *m_sq, m_n;};
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
a m_n
m_sq
3000008000000080400000808800
149
b m_n
m_sq
3
800
Now, watch what happens when we create our new b variable and shallow copy a’s member variables into
it…
Both a’s m_sq pointer…
And b’s m_sq pointer…
Point to a’s original copy of the array!
Page 72
73
Copy Construction
class Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~ Squares(){delete []m_sq;}
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int *m_sq, m_n;};
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
a m_n
m_sq
3000008000000080400000808800
149
b m_n
m_sq
3
800
// b’s d’tor called
But that’s a problem!
Because when b is destructed…
It ends up deleting the array that’s really
owned by variable a!
Operating system, I’m done with the
memory at address 800.
Page 73
74
Copy Construction
class Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~ Squares(){delete []m_sq;}
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int *m_sq, m_n;};
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
// b’s d’tor called
???
Because now, when we try to access a’s array,
we get garbage!!!
a m_n
m_sq
3
800
That’s a big problem!
Page 74
75
Copy Construction
class Squares{public: Squares(int n) { m_n = n; m_sq = new int[n]; for (int j=0;j<n;j++) m_sq[j] = (j+1)*(j+1);
}
~ Squares(){delete []m_sq;}
void printSquares() { for (int j=0;j<m_n;j++) cout << m_sq[j] << endl;
}private:
int *m_sq, m_n;};
int main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
// b’s d’tor called
So what’s the moral of the story?
Any time your class holds pointer
member variables*…
And you make a copy of a class
instance…
BAD THINGS will happen when you
destruct either copy...
* or file objects (e.g., ifstream), network sockets, etc.
Page 75
76
Copy Construction
So how do we fix this?
1. Determine how much memory is allocated by the old variable.
2. Allocate the same amount of memory in the new variable.
3. Copy the contents of the old variable to the new variable.
For such classes, you must define your own copy constructor!
a m_n
m_sq
3
800
000008000000080400000808
149
b m_n
m_sq
3
700
000007000000070400000708
149
Here’s how it works forSquares b = a;
The old variable requires three
slots of memory!
Page 76
77
class Squares{public: Squares(int n) { … } ~ Squares(){ delete[]m_sq; }
// copy constructor
void printSquares() { ... }
private:int *m_sq, m_n;
};
The Copy Constructorint main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
Let’s see how to define our copy constructor!
Squares(const Squares &src) { }
First our copy constructor must determine how much memory is required by the
new instance.
m_n = src.m_n;
This means: “The new instance must
have the same number of array slots as the old
instance.”
Page 77
78
class Squares{public: Squares(int n) { … } ~ Squares(){ delete[]m_sq; }
// copy constructor
void printSquares() { ... }
private:int *m_sq, m_n;
};
The Copy Constructorint main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
Let’s see how to define our copy constructor!
Squares(const Squares &src) { }
Next, our copy constructor must allocate its own copy of any dynamic memory!
m_n = src.m_n;
This ensures that the new instance has its own array and doesn’t share the old
instance’s array!
m_sq = new int[m_n];
Page 78
79
class Squares{public: Squares(int n) { … } ~ Squares(){ delete[]m_sq; }
// copy constructor
void printSquares() { ... }
private:int *m_sq, m_n;
};
The Copy Constructorint main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
Let’s see how to define our copy constructor!
Squares(const Squares &src) { }
Finally, we have to manually copy over the contents of
the original array to our new array.
m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j<m_n;j++) m_sq[j] = src.m_sq[j];
This ensures that the new instance has its own copy of
all of the data!
Page 79
80
class Squares{public: Squares(int n) { … } ~ Squares(){ delete[]m_sq; }
// copy constructor Squares(const Squares &src) { m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j<m_n;j++) m_sq[j] = src.m_sq[j]; }
void printSquares() { ... }
private:int *m_sq, m_n;
};
The Copy Constructorint main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
Let’s watch our correct copy constructor work!
a m_n
m_sq
3000008000000080400000808800
149
b m_n
m_sq
src
3
Operating system, the original variable needed 12 bytes of memory, so
can you reserve 12 bytes for me too?
Sure, I’ll reserve 12 bytes for you at address 900.
000009000000090400000908
900
Now I’ll copy the values from the old array into
my new array.
149
Page 80
81
class Squares{public: Squares(int n) { … } ~ Squares(){ delete[]m_sq; }
// copy constructor Squares(const Squares &src) { m_n = src.m_n; m_sq = new int[m_n]; for (int j=0;j<m_n;j++) m_sq[j] = src.m_sq[j]; }
void printSquares() { ... }
private:int *m_sq, m_n;
};
The Copy Constructorint main(){ Squares a(3); if (...) { Squares b = a; ... }
a.printSquares(); }
a m_n
m_sq
3000008000000080400000808800
149
b m_n
m_sq
3 000009000000090400000908
900
149
// b’s d’tor called
Operating System, can you free the memory at
address 900 for me.
No sweat, homie. Consider it freed.
We’re A-OK, since a still has its own array!
149