Engineering Classes. Objectives At the conclusion of this lesson, students should be able to: Explain why it is important to correctly manage dynamically.

Slides:



Advertisements
Similar presentations
Constructor. 2 constructor The main use of constructors is to initialize objects. A constructor is a special member function, whose name is same as class.
Advertisements

Object Oriented Programming COP3330 / CGS5409.  C++ Automatics ◦ Copy constructor () ◦ Assignment operator =  Shallow copy vs. Deep copy  DMA Review.
Chapter 7: User-Defined Functions II
Pointers Revisited l What is variable address, name, value? l What is a pointer? l How is a pointer declared? l What is address-of (reference) and dereference.
Chapter 15 Memory Management: Four main memory areas for a C++ program: Code: code for instructions, methods, etc. static data: Global variables (declared.
1 Pointers A pointer variable holds an address We may add or subtract an integer to get a different address. Adding an integer k to a pointer p with base.
Rossella Lau Lecture 8, DCO10105, Semester B, DCO10105 Object-Oriented Programming and Design  Lecture 8: Polymorphism & C++ pointer  Inheritance.
 2006 Pearson Education, Inc. All rights reserved Midterm review Introduction to Classes and Objects.
Object Oriented Programming.  OOP Basic Principles  C++ Classes  September 2004  John Edgar 22.
Classes Separating interface from implementation
Pointers and Dynamic Variables. Objectives on completion of this topic, students should be able to: Correctly allocate data dynamically * Use the new.
Operator Overloading and Memory Management. Objectives At the conclusion of this lesson, students should be able to: Overload C++ operators Explain why.
1 Procedural Concept The main program coordinates calls to procedures and hands over appropriate data as parameters.
Shallow Versus Deep Copy and Pointers Shallow copy: when two or more pointers of the same types point to the same memory – They point to the same data.
Review of C++ Programming Part II Sheng-Fang Huang.
Programming Languages and Paradigms Object-Oriented Programming.
Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes
 2006 Pearson Education, Inc. All rights reserved Classes: A Deeper Look.
C++ Programming: Program Design Including Data Structures, Fourth Edition Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes.
Pointer Data Type and Pointer Variables
C++ Programming: From Problem Analysis to Program Design, Fourth Edition Chapter 14: Pointers, Classes, Virtual Functions, and Abstract Classes.
Object Oriented Programming with C++/ Session 6 / 1 of 44 Multiple Inheritance and Polymorphism Session 6.
 2006 Pearson Education, Inc. All rights reserved Classes: A Deeper Look, Part 2.
SEN 909 OO Programming in C++ Final Exam Multiple choice, True/False and some minimal programming will be required.
Computer Science and Software Engineering University of Wisconsin - Platteville 2. Pointer Yan Shi CS/SE2630 Lecture Notes.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 5 An Array Class Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
Constructors CMSC 202. Object Creation Objects are created by using the operator new in statements such as… The following expression invokes a special.
C++ Memory Overview 4 major memory segments Key differences from Java
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 4 Pointers and Dynamic Arrays Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
C++ Programming: From Problem Analysis to Program Design, Second Edition Chapter 13: Pointers You are not responsible for virtual functions (starting on.
Pointers and Dynamic Memory Allocation Copyright Kip Irvine 2003, all rights reserved. Revised 10/28/2003.
Concordia TAV 2002 Comp5421_421 Comp5421 Object Oriented Programming Using C++ Efficiently Lecture 4 (2) Tianxiang Shen Summer 2002 Department of Computer.
Data Structures Using C++ 2E Chapter 3 Pointers. Data Structures Using C++ 2E2 Objectives Learn about the pointer data type and pointer variables Explore.
Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes.
Classes In C++ 1. What is a class Can make a new type in C++ by declaring a class. A class is an expanded concept of a data structure: instead of holding.
CS 376b Introduction to Computer Vision 01 / 23 / 2008 Instructor: Michael Eckmann.
CPSC 252 The Big Three Page 1 The “Big Three” Every class that has data members pointing to dynamically allocated memory must implement these three methods:
Review of Stacks and Queues Dr. Yingwu Zhu. How does a Stack Work? Last-in-First-out (LIFO) data structure Adding an item Push operation Removing an item.
Chapter 10: Classes and Data Abstraction. Objectives In this chapter, you will: Learn about classes Learn about private, protected, and public members.
CS-1030 Dr. Mark L. Hornick 1 Basic C++ State the difference between a function/class declaration and a function/class definition. Explain the purpose.
Functions Illustration of: Pass by value, reference Scope Allocation Reference: See your CS115/215 textbook.
CMSC 202 Advanced Section Classes and Objects: Object Creation and Constructors.
1 Becoming More Effective with C++ … Day Two Stanley B. Lippman
1 Classes II Chapter 7 2 Introduction Continued study of –classes –data abstraction Prepare for operator overloading in next chapter Work with strings.
Chapter 10: Classes and Data Abstraction. Classes Object-oriented design (OOD): a problem solving methodology Objects: components of a solution Class:
Chapter 1 C++ Basics Review (Section 1.4). Classes Defines the organization of a data user-defined type. Members can be  Data  Functions/Methods Information.
Nirmalya Roy School of Electrical Engineering and Computer Science Washington State University Cpt S 223 – Advanced Data Structures C++ Review 2.
Fall 2015CISC/CMPE320 - Prof. McLeod1 CISC/CMPE320 Assignment 3 is due Sunday, the 8 th at 7pm. Today: –Two simple binding examples. –Function Hiding.
Learners Support Publications Constructors and Destructors.
Dynamic Memory Management & Static Class Members Lecture No 7 Object Oriented Programming COMSATS Institute of Information Technology.
Chapter 12: Pointers, Classes, Virtual Functions, Abstract Classes, and Lists.
Memory Management.
Constructors and Destructors
Overview 4 major memory segments Key differences from Java stack
This pointer, Dynamic memory allocation, Constructors and Destructor
Dynamic Memory Review what is static, automatic, dynamic variables? why are dynamic(ally allocated) variables needed what is program stack? function.
Dynamically Allocated Memory
Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes
Object Oriented Programming COP3330 / CGS5409
Overview 4 major memory segments Key differences from Java stack
understanding memory usage by a c++ program
Chapter 15 Pointers, Dynamic Data, and Reference Types
Chapter 15 Pointers, Dynamic Data, and Reference Types
Constructors and Destructors
9-10 Classes: A Deeper Look.
CS410 – Software Engineering Lecture #5: C++ Basics III
9-10 Classes: A Deeper Look.
Classes and Objects Object Creation
SPL – PS3 C++ Classes.
CMSC 202 Constructors Version 9/10.
Presentation transcript:

Engineering Classes

Objectives At the conclusion of this lesson, students should be able to: 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.

Memory Management One of the major program design issues in C++ is memory management. The mishandling of dynamically allocated storage in C++ is among the most serious programming errors made when using the language. Many of these issues can be addressed by designing classes as Concrete Data Types.

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 is specific to the class, all concrete data types have a similar structure. Some author’s refer to this structure as the orthodox canonical class form.

C++ Programs can allocate objects in one of three memory areas. Review The run-time stack The static data area or data segment The heap or free store local variables global and static variables size and amount known at compile time storage allocated at run-time because we don’t know how much or what type of data will be stored when the program is compiled.

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.

Un-initialized pointers should be set to NULL. Pointers should also be set to NULL after calling delete to return storage to the heap.

Destructors All Concrete Data Types must have a destructor if it manages resources through a pointer. When program execution reaches the end of a block in which an object was declared, the storage allocated for 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 any resources that the object may have acquired. The most common resource that needs to be managed is storage allocated from the heap.

Linked Lists The concepts discussed in this slide set will be illustrated using 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. This should be a review of the material presented several weeks ago.

Memory Issues list 3 node 12 node 7 9 This diagram illustrates an example of a linked list. In this example, each node of the list is dynamically allocated from the heap and contains an integer value and a pointer to the next node in the list. null

list 3 node 12 node 7 9 class List { private: Node* headPtr; int length; public:... }; the List class just contains a pointer to the first node in the list, and an integer containing the number of elements in the list. null

list 3 node 12 node 7 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. null

list 3 node 12 node 7 9 So … what happens in this case when the list object goes out of scope? With no destructor, the pointer data member in the list object is relinquished when the object goes out of scope. Without this pointer, the first node, and all subsequent nodes, become inaccessible to the program. Since the storage for these nodes is still owned by the program, we have a memory leak. null some block { List myList;... blah … blah … blah... }

list 3 node 12 node 7 9 null Can you come up with a destructor that keeps The memory leak from happening?

list 3 node 12 node 7 9 head length data next null List::~List { }

list 3 node 12 node 7 9 The following destructor will solve the problem. List::~List( ) { delete head; } head length data next this function returns the value of next null List::~List( ) { Node* p = head; while ( p!=NULL) { Node* pnext = p->getNext( ); delete p; p = pnext; } much better Node::~Node( ) { delete next; } delete on NULL ptr is a no op!

list 3 node 12 node 7 9 List::~List( ) { Node* p = head; while ( p!=NULL) { Node* pnext = p->getNext( ); delete p; p = pnext; } head length data next this function returns the value of next null p pnext

list 3 node 7 9 List::~List( ) { Node* p = head; while ( p!=NULL) { Node* pnext = p->getNext( ); delete p; p = pnext; } head length node 12 data next this function returns the value of next null p pnext

list 3 node 7 9 List::~List( ) { Node* p = head; while ( p!=NULL) { Node* pnext = p->getNext( ); delete p; p = pnext; } head length this function returns the value of next null p pnext

Assignment Operator We just illustrated how to manage the memory allocated dynamically for Node objects when the list goes out of scope. However, the automatic invocation of the destructor when the object goes out of scope introduces another serious problem. Consider the following …

list 3 node 12 node 7 9 list_a list 2 node 21 node 6 list_b null

list 3 node 12 node 7 9 list_a list 2 node 21 node 6 list_b list_a = list_b; the default assignment operator does a member-by member copy of each data member in the list objects. 2 Problem: The pointer to this Data has been lost. Memory Leak! null

list 2 node 12 node 7 9 list_a list 2 node 21 node 6 list_b Now … suppose list_b goes out of scope. Our destructor, as specified, cleans up the list, returning the storage for each node to the heap. Problem: the pointer in list_a points to memory no longer owned by the program. null

list 2 node 12 node 7 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! This could totally destroy the memory manager! null

We solve this problem by overloading the assignment 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.

list 3 node 12 node 7 9 list_a list 2 node 21 node 6 list_b null Free this storage

list 3 list_a list 2 node 21 node 6 list_b null node 21 node 6 null Make a copy the entire list … 2

const List& List::operator=(const List& b) { if (this ==&b) return *this; it is customary to name the parameter ‘b’ always pass the operand as a constant reference return a List reference to allow multiple assignment first, check to make sure that we are not doing the assignment a = a; We don’t want to clean up storage for a if this is the case.

const List& List::operator=(const List& b) { if (this ==&b) return *this; Node* p = head; while (p != NULL) { Node* pnext = p->getNext( ); delete p; p = pnext; } this code cleans up the storage allocated to the left hand list. Note: It’s the same code we wrote for the destructor.

Next, we are going to do the copy. We are going to do what is called a deep copy. That is, 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 what they point to.

length = b.length; p = NULL; Node* q = b.getHead( ); while (q != NULL) { Node* n = new Node; n->setNext (NULL); n->setData (q->getData( )); if (p == NULL) head = n; else p->setNext (n); p = n; q = q->getNext ( ); } return *this; start by copying the length data. set the Node* p to Null, we will use this later. then declare another Node* q, and set it to the head data member in list b.

list 2 list_a list 2 node 6 list_b q n p NULL 21 length = b.length; P = NULL; Node *q = b.getHead( );

length = b.length; p = NULL; Node* q = b.getHead( ); while (q != NULL) { Node* n = new Node; n->setNext (NULL); n->setData (q->getData( )); if (p == NULL) head = n; else p->setNext (n); p = n; q = q->getNext ( ); } return *this; Now, allocate storage for the first node in the new list. set its pointer to the next node to NULL. get the data member of the current node in the right-hand list and store its value in this new node.

list 2 list_a list 2 node 6 list_b q n p NULL 21 q points to the current node in the right hand list n points to the new node just created n -> setNext (NULL); n -> setData (q.getData( )); Node *n = new Node;

length = b.length; p = NULL; Node* q = b.getHead( ); while (q != NULL) { Node* n = new Node; n->setNext (NULL); n->setData (q.getData( )); if (p == NULL) head = n; else p->setNext (n); p = n; q = q->getNext ( ); } return *this; If this is the first node store its pointer in the list object.

list 2 list_a list 2 node 6 list_b q n p NULL 21 head if (p == NULL) head = n; 21

length = b.length; p = NULL; Node* q = b.getHead( ); while (q != NULL) { Node* n = new Node; n->setNext (NULL); n->setData (q.getData( )); if (p == NULL) head = n; else p->setNext (n); p = n; q = q->getNext ( ); } return *this; set to point to the end node in left hand list, the one we just created set to point to the next node in the right hand list.

list 2 list_a list 2 node 6 list_b q n p NULL head p = n; 21 q = q->getNext( );

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

list 2 list_a list 2 node list_b list_a = list_b; q n p NULL head 21 Node* n = new Node; n->setNext (NULL); n->setData (q.getData( )); NULL 6

list 2 list_a list 2 node list_b list_a = list_b; q n p head 21 NULL 6 6 else p->setNext (n); p is not null, so … NULL p = n; q = q->getNext ( );

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

Copy Constructor We have fixed the assignment operator so that is correctly 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 function exits, these variables go out of scope and are destroyed. This will cause similar problems to the ones we just discussed with the default assignment operator.

list_a 3 node 12 node 7 9 Consider the list shown. What happens in the function invocation double average (List a);

list_a 3 node 12 node 7 9 stack when the function is called, a copy of the list object goes on the stack. The default is a shallow copy …. 3

list_a 3 node 12 node 7 9 stack when the function exits, all of the variables associated with the function go out of scope. This includes the copy of the list object passed on the stack. When it goes out of scope, its destructor is called … 3 Oh-oh!

The Copy Constructor List::List(const List& b) { length = b.length; Node* p =NULL; Node* q = b.head; while (q != NULL) { Node* n = new Node; n->getNext (NULL); n->setData (q->getData( )); if (p == NULL) head = n; else p->setNext (n); p = n; q = q.getNext( ); } If this looks familiar, it is because it is the same code we used to copy the object in the overloaded assignment operator. this is a copy constructor because it takes an object of its own type as a parameter. the compiler invokes this code automatically whenever it needs to create a copy of the object.

Factoring Common Code There is a lot of common code between the destructor, the assignment operator, and the copy constructor. We can factor this common free and copy code out. Then the destructor, copy constructor, and assignment operator look as shown in the following slide.

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; }

The Run-Time Stack A stack is a first-in last-out data structure.

The Run-Time Stack Data comes off of the stack in the opposite order of how it was out on.

The Run-Time Stack When a function is invoked, space is allocated on the stack for: the function’s parameters the function’s return address the function’s locally declared variables This is called an Activation Record or Stack Frame parameters return address Local variables Stack frame for a( ) parameters return address Local variables Stack frame for b( )

Reference Counts Suppose that two objects share a common value: value How would you manage this if the value were dynamically allocated?

Reference Counts Suppose that two objects share a common value: value How would you manage this if the value were dynamically allocated? 2 Reference Count

Reference Counts What would the destructor do in this case? value 2 Reference Count 1

The Bridge Pattern Also known as the Handle/Body pattern, the bridge pattern provides a way for the programmer to completely hide the details of an implementation.

C++ provides encapsulation and data abstraction by using the private keyword to hide the details of a class’s implementation. However, the private keyword only prevents access to the class’s private elements, it does not really hide them. A programmer only need look at the class’s header file to glean a great deal of information about how a class is implemented. What if you really want to hide the details? For example, what if you have a proprietary algorithm you don’t want users of your class to know about.

Example class Handle { public: Handle ( ); ~Handle( ); void foo ( ); private: Impl* _theImpl; }; The Impl class contains the actual implementation details. The pointer _theImpl is used to pass a request on to an object of the Impl class. For example, in the Handle class, the foo( ) function might be written as void Handle::foo ( ) { _theImpl -> foo( ); }

A good paper on the Bridge design pattern can be found here: