67
Operator Overloading and Memory Management

Operator Overloading and Memory Management

Embed Size (px)

DESCRIPTION

Operator Overloading and Memory Management. Objectives. At the conclusion of this lesson, students should be able to: Overload C++ operators Explain why it is important to correctly manage dynamically allocated storage. Write programs that correctly use - PowerPoint PPT Presentation

Citation preview

Page 1: Operator Overloading  and Memory Management

Operator Overloading and

Memory Management

Page 2: Operator Overloading  and Memory Management

Objectives

At the conclusion of this lesson, students should be able to:

Overload C++ operators Explain why it is important to correctly manage dynamically allocated storage. Write programs that correctly use * Destructors to return dynamically allocated storage to the system. * Overloaded assignment operators to make a deep copy when necessary and return dynamically allocated storage to the system. * Copy constructors to make a deep copy when necessary.

Page 3: Operator Overloading  and Memory Management

Operator Overloading

In order to do write some of the code thatIs needed to manage memory correctly, wewill have to overload an operator in C++.

Page 4: Operator Overloading  and Memory Management

Suppose that we have a class called Region, That represents a rectangular region.

Region

- length: int- width: int

+ Region(int: int:)+ getWidth( ) :int+ getLength( ) :int

Page 5: Operator Overloading  and Memory Management

We know how to add two primitive datatypes together, but can we add two Regions?

Region r1(4,5);Region r2(6,3);Region r3 = r1 + r2:

We can, if we overload the + operator!

When we overload an operator, we tellthe compiler what to do when the operator

is used on objects of a given class.

Page 6: Operator Overloading  and Memory Management

The code to overload an operator can usuallybe written as a member function, or as a

non-member function of a class.

Page 7: Operator Overloading  and Memory Management

Overloading the + operator as a member Of the Region class.

Page 8: Operator Overloading  and Memory Management

The + operator is a binary operator – it has two operands.

Some Terminology

c = b + c;

the left-handoperand

theoperator

The right-handoperand

Page 9: Operator Overloading  and Memory Management

The + operator is a binary operator – it has two operands.

Some Terminology

c = b + c;

The message is sentto this object. It is

sometimes called theimplicit object.

theoperator

the right-hand operandis passed as a parameter

to the function.

Page 10: Operator Overloading  and Memory Management

The function looks like this:

Region Region::operator+(const Region& rho){ int newLength = length + rho.length; int newWidth = width + rho.width; Region rtnR(newWidth, newLength);}

Page 11: Operator Overloading  and Memory Management

Region Region::operator+(const Region& rho){ int newLength = length + rho.length; int newWidth = width + rho.width; Region rtnR(newWidth, newLength); return rtnR;}

The name of the function is the word“operator” followed by the symbol +

The function is a memberof the Region class

It returns a Region object.It is returned by value..

The function takes the right handoperand as its parameter. Remember topass objects by constant reference.

Page 12: Operator Overloading  and Memory Management

The compiler generates this function call

r3 = r1.operator+(r2);

length = 3width = 4

length = 5width = 2

r1 r2length = ?width = ?

r3

= + ;

The messageis sent to this object.

This object ispassed as theparameter

Page 13: Operator Overloading  and Memory Management

r3 = r1.operator+(r2);

length = 3width = 4

length = 5width = 2

r1 r2length = ?width = ?

r3

= + ;

The messageis sent to this object.

This object ispassed as theparameter

Region Region::operator+(const Region& rho){ int newLength = length + rho.length; int newWidth = width + rho.width; Region rtnR(newWidth, newLength);}

These belong to r1 (the implicit object )

Page 14: Operator Overloading  and Memory Management

You could write this function as anon-member function. Then it wouldlook like this:

r3 =operator+(r1, r2);

length = 3width = 4

length = 5width = 2

r1 r2length = ?width = ?

r3

= + ;

This object is passedas the 1st parameter

This object is passedas the 2nd parameter

Region operator+(const Region& lho, const Region& rho){ int newLength = lho.getLength( ) + rho.getLength( ); int newWidth = lho.getWidth( ) + rho.getWidth( ); Region rtnR(newWidth, newLength);} Must use a public getter

Page 15: Operator Overloading  and Memory Management

When overloading an operator there are timeswhen you cannot write the code as a member function.

A good example is the stream insertion operator.It must be written a non-member function.

Page 16: Operator Overloading  and Memory Management

If a member function, the compiler would generatethis function call

cout.operator<<(const Region& r1);

length = 3width = 4

r1cout

<< ;

but we can’t add code to the ostream classto overload the stream insertion operator.

Page 17: Operator Overloading  and Memory Management

Overloading the Stream Insertion Operator

Page 18: Operator Overloading  and Memory Management

Because we write this code as a non-memberfunction, it will take two parameters, like this:

ostream& operator<< (ostream& out, const Region& r1);

length = 3width = 4

r1cout

<< ;

The function mustreturn a stream object.

The stream parametercan’t be constant … we are changing it.

Page 19: Operator Overloading  and Memory Management

ostream& operator<< (ostream& out, const Region& r1){ out << “Width = “ << r1.getWidth( ); out += “Length = “ << r1.getLength( ); return out;}

length = 3width = 4

r1cout

<< ;

Put whatever data you wantinto the stream. You have to usepublic functions in the Region class.

Then just return the stream object.

Page 20: Operator Overloading  and Memory Management

Memory ManagementOne of the major program design issues in C++is memory management. The mishandling of dynamically allocated storage in C++ is amongthe most serious programming errors made whenusing the language.

Many of these issues can be addressed bydesigning classes as Concrete Data Types.

Page 21: Operator Overloading  and Memory Management

Concrete Data Types

One of the goals of good software development in C++ is to construct each class so that it appears, to the applications programmer, to be equivalent to a built-in type for the language.That is, it is well behaved in all of the ways that a standard built-in data type is well behaved.

A C++ class written in this way has been termed a “concrete data type''. Although in detail, the implementation of a class isspecific to the class, all concrete data types have a similar structure. Some author’s refer to this structure as the orthodox canonical class form.

Page 22: Operator Overloading  and Memory Management

C++ Programs can allocate objects in one of threememory areas.

Review

The run-time stackThe static data area or data segmentThe heap or free store

local variables

global and staticvariables

size and amountknown at compile

time

storage allocated at run-timebecause we don’t know how muchor what type of data will be stored

when the program is compiled.

Page 23: Operator Overloading  and Memory Management

An object is allocated on the heap using the new operator.

The allocated object has no name, but is referenced through a pointer returned by the new operator.

Storage allocated using new must be recycled back to the heap when the storage is no longer required. Storage that is no longer accessible, but has not been returned to the heap is called a memory leak.

Page 24: Operator Overloading  and Memory Management

Un-initialized pointers should be set to nullptr.

Pointers should also be set to nullptr after calling delete to return storage to the heap.

Page 25: Operator Overloading  and Memory Management

DestructorsAll Concrete Data Types must have a destructor if itmanages resources through a pointer.

When program execution reaches the end of a blockin which an object was declared, the storage allocatedfor that object on the stack is relinquished.

If a destructor is defined for the class to which the object belongs, the destructor is called first.

The purpose of the destructor is to clean up anyresources that the object may have acquired. Themost common resource that needs to be managed isstorage allocated from the heap.

Page 26: Operator Overloading  and Memory Management

Linked Lists

The concepts discussed in this slide set will be illustratedusing a linked list. Before going through the examples, it will be necessary that you understand what a linked list is and how they are used.

Page 27: Operator Overloading  and Memory Management

Memory Issues

list

3

node

12

node

7

node

9

This diagram illustrates an example ofa linked list. In this example, each node of thelist is dynamically allocated from the heap andcontains an integer value and a pointer to thenext node in the list.

nullptr

Page 28: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

class List{ private: Node* head; int length; public: . . .};

the List class just containsa pointer to the first nodein the list, and an integer

containing the number ofelements in the list.

nullptr

Page 29: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

class Node{ private: int data; Node* next; public: Node* getNext( ); …};

Each node object contains an integer data member and a pointer to the next node. The storage for each node is allocated from the heap as it is needed.

nullptr

Page 30: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

So … what happens in this case when the listobject goes out of scope?

With no destructor, the pointer data memberin the list object is relinquished when the objectgoes out of scope. Without this pointer, the firstnode, and all subsequent nodes, become inaccessibleto the program. Since the storage for these nodes isstill owned by the program, we have a memory leak.

some block{ List myList; . . . blah … blah … blah . . .}

nullptr

Page 31: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

Can you come up with a destructor that keepsThe memory leak from happening?

nullptr

Page 32: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

head

length

data next

List::~List{

}

nullptr

Page 33: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

The following destructor will solvethe problem.

List::~List( ){ Node* p = head; while ( p!=nullptr) { Node* pnext = p->getNext( ); delete p; p = pnext; }}

head

length

data next

this function returns thevalue of next

nullptr

Page 34: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

List::~List( ){ Node* p = head; while ( p!=nullptr) { Node* pnext = p->getNext( ); delete p; p = pnext; }}

head

length

data next

this function returns thevalue of next

p pnext

nullptr

Page 35: Operator Overloading  and Memory Management

list

3

node

7

node

9

List::~List( ){ Node* p = head; while ( p!=nullptr) { Node* pnext = p->getNext( ); delete p; p = pnext; }}

head

length

node

12

data next

this function returns thevalue of next

p pnext

nullptr

Page 36: Operator Overloading  and Memory Management

list

3

node

7

node

9

List::~List( ){ Node* p = head; while ( p!=nullptr) { Node* pnext = p->getNext( ); delete p; p = pnext; }}

head

length

this function returns thevalue of next

p pnext

nullptr

Page 37: Operator Overloading  and Memory Management

Assignment Operator

We just illustrated how to manage the memoryallocated dynamically for Node objects when thelist goes out of scope. However, the automatic invocation of the destructor when the object goesout of scope introduces another serious problem.

Consider the following …

Page 38: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

list_a

list

2

node

21

node

6

list_b

nullptr

nullptr

Page 39: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

list_a

list

2

node

21

node

6

list_b

list_a = list_b;

the default assignment operator does a member-bymember copy of each data member in the list objects.

2

Problem: The pointer to thisData has been lost. Memory Leak!

nullptr

nullptr

Page 40: Operator Overloading  and Memory Management

list

2

node

12

node

7

node

9

list_a

list

2

node

21

node

6

list_b

Now … suppose list_b goes out of scope.

Our destructor, as specified, cleans upthe list, returning the storage for eachnode to the heap.

Problem: the pointerin list_a points to memoryno longer owned by the program.

nullptr

nullptr

Page 41: Operator Overloading  and Memory Management

list

2

node

12

node

7

node

9

list_a

Storage belonging to the heap.

Adding insult to injury, what happens when list_a goes out of scope?

this storage gets returned twice! Thiscould totally destroythe memory manager!

nullptr

Page 42: Operator Overloading  and Memory Management

We solve this problem by overloading theassignment operator in the List class.

The assignment operator must do two things:

list_a = list_b;

Free the storage used by the left operand (list_a) Make a copy the entire data structure of the right operand (list_b) and point to it in the left operand -– do a deep copy.

Page 43: Operator Overloading  and Memory Management

list

3

node

12

node

7

node

9

list_a

list

2

node

21

node

6

list_b

nullptr

nullptr

Free this storage

Page 44: Operator Overloading  and Memory Management

list

3list_a

list

2

node

21

node

6

list_b

nullptr

node

21

node

6nullptr

Make a copy the entire list …

2

Page 45: Operator Overloading  and Memory Management

const List& List::operator=(const List& b){ if (this ==&b) return *this;

it is customary to name the parameter ‘b’

always pass the operandas a constant reference

return a List referenceto allow multiple assignment

first, check to make surethat we are not doing theassignment a = a; We don’twant to clean up storage fora if this is the case.

Page 46: Operator Overloading  and Memory Management

const List& List::operator=(const List& b){ if (this ==&b) return *this;

Node* p = head; while (p != nullptr) { Node* pnext = p->getNext( ); delete p; p = pnext; }

this code cleans upthe storage allocatedto the left hand list. Note: It’s the same code we wrote for the destructor.

Page 47: Operator Overloading  and Memory Management

Next, we are going to do the copy. We aregoing to do what is called a deep copy. Thatis, we are going to create a complete copy of the data structure that is on the right hand side.

A shallow copy only copies pointers, not whatthey point to.

Page 48: Operator Overloading  and Memory Management

length = b.length;p = nullptr;Node* q = b.getHead( );while (q != nullptr){ Node* n = new Node; n->setNext (nullptr); n->setData (q->getData( )); if (p == nullptr) head = n; else p->setNext (n); p = n; q = q->getNext ( );}return *this;

start by copying thelength data. set the Node* p to nullptr

we will use this later.

then declare anotherNode* q, and set it to thehead data member in list b.

Page 49: Operator Overloading  and Memory Management

list

2

list_a

list

2

nodenode

6

list_b

q

n

pnullptr

21

length = b.length;P = nullptr;Node *q = b.getHead( );

Page 50: Operator Overloading  and Memory Management

length = b.length;p = nullptr;Node* q = b.getHead( );while (q != nullptr){ Node* n = new Node; n->setNext (nullptr); n->setData (q->getData( )); if (p == nullptr) head = n; else p->setNext (n); p = n; q = q->getNext ( );}return *this;

Now, allocate storage forthe first node in the newlist.

set its pointer to thenext node to nullptr.

get the data member of thecurrent node in the right-handlist and store its value in thisnew node.

Page 51: Operator Overloading  and Memory Management

list

2list_a

list

2

nodenode

6

list_b

q

n

pnullptr

nullptr

21

q points to the current nodein the right hand list

n points to the new node just created

n -> setNext (nullptr);n -> setData (q.getData( ));

Node *n = new Node;

21

Page 52: Operator Overloading  and Memory Management

length = b.length;p = nullptr;Node* q = b.getHead( );while (q != nullptr){ Node* n = new Node; n->setNext (nullptr); n->setData (q.getData( )); if (p == nullptr) head = n; else p->setNext (n); p = n; q = q->getNext ( );}return *this;

If this is the first nodestore its pointer in thelist object.

Page 53: Operator Overloading  and Memory Management

list

2list_a

list

2

nodenode

6

list_b

q

n

pnullptr

nullptr

21

head

if (p == NULL) head = n;

21

Page 54: Operator Overloading  and Memory Management

length = b.length;p = nullptr;Node* q = b.getHead( );while (q != nullptr){ Node* n = new Node; n->setNext (nullptr); n->setData (q.getData( )); if (p == nullptr) head = n; else p->setNext (n); p = n; q = q->getNext ( );}return *this;

set to point to the endnode in left hand list,the one we just created set to point to the next

node in the right hand list.

Page 55: Operator Overloading  and Memory Management

list

2list_a

list

2

nodenode

6

list_b

q

n

p

nullptr

head

p = n;

21

21

q = q->getNext( );

Page 56: Operator Overloading  and Memory Management

We have copied the List Object and thefirst Node. Since q is not null (it points toa node) go through the while block again.

Page 57: Operator Overloading  and Memory Management

list

2list_a

list

2

nodenode

list_b

list_a = list_b;

q

n

p

nullptr

head

21

21

Node* n = new Node;n->setNext (nullptr);n->setData (q.getData( ));

nullptr

6

Page 58: Operator Overloading  and Memory Management

list

2list_a

list

2

nodenode

list_b

list_a = list_b;

q

n

p

head

21

21

nullptr

6

6

else p->setNext (n);

p is not null, so …

nullptr

p = n;q = q->getNext ( );

Page 59: Operator Overloading  and Memory Management

We have successfully copied the secondnode from the right-hand list. q is now= nullptr, so we drop out of the loop.

Page 60: Operator Overloading  and Memory Management

Copy Constructor

We have fixed the assignment operator so that iscorrectly creates a copy of the object. However,objects also get copied when passed by value. When a function is called, all of the function arguments are copied into local variables associated with the function. When the functionexits, these variables go out of scope and are destroyed. This will cause similar problems to theones we just discussed with the default assignment operator.

Page 61: Operator Overloading  and Memory Management

list_a

3

node

12

node

7

node

9

Consider the list shown. What happens in thefunction invocation

double average (List a);

Page 62: Operator Overloading  and Memory Management

list_a

3

node

12

node

7

node

9

stack

when the function is called, a copyof the list object goes on the stack.The default is a shallow copy ….

3

Page 63: Operator Overloading  and Memory Management

list_a

3

node

12

node

7

node

9

stack

when the function exits, all of thevariables associated with the functiongo out of scope. This includes thecopy of the list object passed on thestack. When it goes out of scope, itsdestructor is called …

3

Oh-oh!

Page 64: Operator Overloading  and Memory Management

The Copy Constructor

List::List(const List& b){ length = b.length; Node* p =nullptr; Node* q = b.head; while (q != nullptr) { Node* n = new Node; n->getNext (nullptr); n->setData (q->getData( )); if (p == nullptr) head = n; else p->setNext (n); p = n; q = q.getNext( ); }}

If this looks familiar,it is because it is the samecode we used to copy theobject in the overloadedassignment operator.

this is a copy constructorbecause it takes an object of its own type as a parameter.

the compiler invokesthis code automaticallywhenever it needs to createa copy of the object.

Page 65: Operator Overloading  and Memory Management

Copy Constructor

It is important to note that like a normal constructor, the function of the copy constructor is to initialize the data members of the object that just got created.

The compiler generates the code to create the objectwhen you do a pass by value.

Page 66: Operator Overloading  and Memory Management

Factoring Common Code

There is a lot of common code between thedestructor, the assignment operator, and thecopy constructor. We can factor this commonfree and copy code out. Then the destructor,copy constructor, and assignment operatorlook as shown in the following slide.

Page 67: Operator Overloading  and Memory Management

List::List (const List& b){ copy(b);}

List::~List( ){ free( );}

const List& List::operator=(const List& b){ if (this != &b) { free( ); copy(b); } return *this;}