15 – Sequential Containers

Slides:



Advertisements
Similar presentations
Composition CMSC 202. Code Reuse Effective software development relies on reusing existing code. Code reuse must be more than just copying code and changing.
Advertisements

Object Oriented Programming COP3330 / CGS5409.  C++ Automatics ◦ Copy constructor () ◦ Assignment operator =  Shallow copy vs. Deep copy  DMA Review.
6/10/2015C++ for Java Programmers1 Pointers and References Timothy Budd.
Rossella Lau Lecture 8, DCO10105, Semester B, DCO10105 Object-Oriented Programming and Design  Lecture 8: Polymorphism & C++ pointer  Inheritance.
@ Zhigang Zhu, CSC212 Data Structure - Section FG Lecture 10 The Bag and Sequence Classes with Linked Lists Instructor: Zhigang Zhu Department.
ARRAYS AND POINTERS Although pointer types are not integer types, some integer arithmetic operators can be applied to pointers. The affect of this arithmetic.
The Rest of the Story.  Constructors  Compiler-generated  The Initializer List  Copy Constructors  Single-arg (conversion ctors)  The Assignment.
CS212: Object Oriented Analysis and Design Lecture 6: Friends, Constructor and destructors.
Xiaoyan Li, CSC211 Data Structures Lecture 10 The Bag and Sequence Classes with Linked Lists Instructor: Prof. Xiaoyan Li Department of Computer.
Pointers Pointer a data type stores a memory address points to whatever the memory location contains A pointer is a variable that can store a memory address.
1 Inside the Vector Class: with additional needed methods CPS212CPS212 Gordon College.
Pointers and Dynamic Memory Allocation Copyright Kip Irvine 2003, all rights reserved. Revised 10/28/2003.
More C++ Features True object initialisation
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved Stacks.
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:
C arrays are limited: -they are represented by pointers (which may or may not be valid); -Indexes not checked (which means you can overrun your array);
CMSC 202, Version 3/02 1 Copy Constructors and Overloaded Assignment.
Quick Review of OOP Constructs Classes:  Data types for structured data and behavior  fields and methods Objects:  Variables whose data type is a class.
Engineering Classes. Objectives At the conclusion of this lesson, students should be able to: Explain why it is important to correctly manage dynamically.
Nirmalya Roy School of Electrical Engineering and Computer Science Washington State University Cpt S 223 – Advanced Data Structures C++ Review 2.
An Array-Based Implementation of the ADT List
Memory Management.
Yan Shi CS/SE 2630 Lecture Notes
Motivation for Generic Programming in C++
Pointers and Dynamic Arrays
Topic: Classes and Objects
Learning Objectives Pointers as dada members
CS 215 Final Review Ismail abumuhfouz Fall 2014.
Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes
Chapter 1 C++ Basics Review
Operator overloading Conversions friend inline
Operator overloading Conversions friend inline
CISC181 Introduction to Computer Science Dr
Operator overloading Conversions friend inline
Class: Special Topics Copy Constructors Static members Friends this
Wednesday, February 28, 2018 Announcements… For Today…
Templates.
Sequential Containers
Memberwise Assignment / Initialization
This pointer, Dynamic memory allocation, Constructors and Destructor
The Bag and Sequence Classes with Linked Lists
Dynamically Allocated Memory
Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes
Array Lists Chapter 6 Section 6.1 to 6.3
Object Oriented Programming COP3330 / CGS5409
Object Oriented Programming COP3330 / CGS5409
Classes with Dynamically Allocated Data
understanding memory usage by a c++ program
Chapter 15 Pointers, Dynamic Data, and Reference Types
Automatics, Copy Constructor, and Assignment Operator
15 – Sequential Containers
14 – Sequential Containers
Chapter 15 Pointers, Dynamic Data, and Reference Types
Constructors and Other Tools
The Standard Template Library
C++ Templates L03 - Iterator 10 – Iterator.
9-10 Classes: A Deeper Look.
CSC212 Data Structure - Section RS
Java Programming Language
COP 3330 Object-oriented Programming in C++
Class: Special Topics 2 For classes using memory allocation
EECE.3220 Data Structures Instructor: Dr. Michael Geiger Spring 2019
Destructors, Copy Constructors & Copy Assignment Operators
Chapter 3 Lists, Stacks, and Queues
Destructors, Copy Constructors & Copy Assignment Operators
9-10 Classes: A Deeper Look.
Copy Constructors and Overloaded Assignment
14 – Sequential Containers
Chapter 6 – Queues and Deques
SPL – PS3 C++ Classes.
Presentation transcript:

15 – Sequential Containers 4.3 Implementation of a Vector Class 4.4 The Copy Constructor, Assignment Operator, and Destructor 15 – Sequential Containers

Sequential Containers

Tip #12: new vs. malloc Differences between malloc and new: Sequential Containers Differences between malloc and new: Calling Constructors: new calls constructors, malloc() does not. In fact primitive data types (char, int, float.. etc) can also be initialized with new. Operator vs function: new is an operator, malloc() is a function. Return type: new is type safe and returns exact data type, malloc() returns void *. Failure Condition: On failure, malloc() returns NULL, new Throws. Memory: In case of new, memory is allocated from free store where as in malloc() memory allocation is done from heap. Overriding: We are allowed to override new operator where as we can not override the malloc() function legally. Size: Required size of memory is calculated by compiler for new, where as we have to manually calculate size for malloc(). The short answer is: Fundamentally, malloc is a C feature and new is a C++ feature. Don't use malloc with C++ without a really good reason for doing so.

An Even Better TIP… We believe all that God has revealed, all that He does now reveal, and we believe that He will yet reveal many great and important things pertaining to the Kingdom of God. —Articles of Faith 1:9

4.3, pgs. 240-246 4.3 Implementation of a Vector Class The Default Constructor The swap Function The Subscripting Operator The push_back Function The insert Function The erase Function The reserve Function Performance of the KW::Vector 4.3, pgs. 240-246

A Vector Class Object Sequential Containers template<typename T> class Vector { private: // Data fields /** The initial capacity of the array */ static const size_t INITIAL_CAPACITY = 10; /** The current capacity of the array */ size_t current_capacity; /** The current num_items of the array */ size_t num_items; /** The array to contain the data */ T* the_data; public: // Member Functions ... }; We will implement a simplified version of the vector class. The physical size of the array is indicated by the data field current_capacity (type size_t because it must be non-negative) The number of data items stored is indicated by the data field num_items

Vector<int> myVector(); Sequential Containers template<typename T> class Vector { private: // Data fields ... public: // Member Functions /** Construct an empty vector w/default capacity */ Vector<T>() : current_capacity(INITIAL_CAPACITY), the_data(new T[INITIAL_CAPACITY]), num_items(0) {} }; Initializer List. current_capacity = INITIAL_CAPACITY; the_data = new T[INITIAL_CAPACITY]; num_items = 0;

myVector[1]; Sequential Containers template<typename T> class Vector { private: // Data fields ... public: // Member Functions /** Subscripting operator */ T& operator[](size_t index) // Verify valid index. if (index < 0 || index >= num_items) throw std::out_of_range("index to operator[] is out of range"); } return the_data[index]; }; Because this is a template class, all of the code must be in the header or in a file included by the header . In the STL vector, only the at function validates the index.

myVector.push_back(10); Sequential Containers void push_back(const T& the_value) { // Make sure there is space for the new item. if (num_items == current_capacity) reserve(2 * current_capacity); /* Allocate an expanded array */ } // Insert the new item. the_data[num_items] = the_value; num_items++;

The reserve(size) Function Sequential Containers void reserve(size_t new_capacity) { if (new_capacity > current_capacity) if (new_capacity > 2 * current_capacity) current_capacity = new_capacity; else current_capacity *= 2; // Double the capacity. T* new_data = new T[current_capacity]; for (size_t i = 0; i < num_items; i++) new_data[i] = the_data[i]; // Copy the data over. delete[] the_data; // Free old memory. the_data = new_data; // Point to the new data. } Doubling spreads out the cost of copying.  Doubling an array of size n allows us to add n more items before another array copy.  Therefore, we can add n new items after we have copied over n existing items.  Although reallocation is O(n), we have to do a reallocation only after n items are added.  This averages out to 1 copy per add, so reallocation is effectively an O(1) operation.  push_back() is performed in amortized constant time.

myVector.insert(2, 20); void insert(size_t index, const T& the_value) Sequential Containers void insert(size_t index, const T& the_value) { if (index > num_items) // Validate index. throw std::out_of_range("index to insert is out of range"); } if (num_items == current_capacity) // Check for room reserve(2 * current_capacity); // Allocate an expanded array for (size_t i = num_items; i > index; i--) // Open a slot the_data[i] = the_data[i - 1]; the_data[index] = the_value; // Insert new item num_items++;

myVector.erase(3); void erase(size_t index) { // Validate index. Sequential Containers void erase(size_t index) { // Validate index. if (index > num_items) throw std::out_of_range ("index to erase is out of range"); } // Move items below the removed one up. for (size_t i = index + 1; i < num_items; i++) the_data[i - 1] = the_data[i]; num_items--;

Performance of Vector Sequential Containers The functions operator[] and at are each a few lines of code and contain no loops - execute in constant time, or O(1). If we insert into (or remove from) the middle of a vector, then at most n items have to be shifted which is O(n). What if we have to reallocate before we can insert? Recall that we spread out the cost of copying so that effectively it is an O(1) operation, so the insertion is still O(n) . Even if we don’t spread out the cost of copying, the copy operation is still O(n), so the worst case merely doubles the cost.

4.4 The Copy Constructor, Assignment Operator, and Destructor Copying Objects and the Copy Constructor Shallow Copy versus Deep Copy Assignment Operator The Destructor 4.4, pgs. 247-251

Copy Constructor Sequential Containers We want a copy of an object to be an independent copy, which means we should be able to modify one of the objects without affecting the other. Copying of primitive types is straightforward—the values are duplicated and placed in the target locations . For class types, copying is done by a class's copy constructor: MyClass(const MyClass& other); MyClass& operator=(const MyClass& other); The copy constructor is invoked automatically: when an object is passed to a function by value. when an object is returned from a function. when an object is initialized with another object of the same class. when the compiler generates a temporary object.

Default Copy Constructor Sequential Containers A default constructor is a constructor which can be called without any arguments. Provided implicitly by the compiler - Any user defined constructor will prevent the compiler from implicitly declaring a default constructor. A copy constructor is a constructor which can be called with a single argument of the same type. Providing other constructors will not prevent the compiler from implicitly declaring a. The compiler calls copy constructors certain well defined contexts variable definitions and type conversions. To summarize, The compiler will provide an implicit copy constructor even if the class has other user defined constructors, provided none of those constructors can be considered copy constructors. And if you provide a user defined copy constructor, the compiler will not provide an implicitly declared default copy constructor.

Shallow Copy versus Deep Copy Sequential Containers Referring back to our vector class, a copy of the size_t fields current_capacity and num_items creates independent copies of the variables. However, copying the pointer value the_data does not create an independent copy. Copying a pointer this way is considered a shallow copy. 1 2 3 4 5 Vector<int> v1 num_items = 5 current_capacity = 8 int* the_data = _____ Vector<int> v2 = v1; Vector<int> v2 num_items = 5 current_capacity = 8 int* the_data = _____

Deep Copy Sequential Containers We need to create an independent copy or a deep copy of the underlying array so that v1.the_data and v2.the_data point to different arrays, making vector v2 a deep copy of vector. /** Make a (deep) copy of a vector. @param other The vector to be copied */ Vector<T>(const Vector<T>& other) : current_capacity(other.capacity), num_items(other.num_items), the_data(new T[other.current_capacity]) { for (size_t i = 0; i < num_items; i++) the_data[i] = other.the_data[i]; }

Copying Objects To create an independent copy of an object, the Sequential Containers To create an independent copy of an object, the Copy constructor is called when a new object is created from an existing object, as a copy of the existing object. Assignment operator is called when a already initialized object is assigned a new value from another existing object. MyClass t1, t2; MyClass t3 = t1; // copy constructor (t3 is new) t2 = t1; // assignment operator (t2 exists) t2.operator=(t1); // assignment operator (equivalent) Assignment of primitive types is straightforward—the value is duplicated and placed in the target location. Every class has a default assignment operator which makes a copy of each data field of the source and places it into the corresponding data field of the target . If a class type, that class’s assignment operator is used. The default assignment operator makes a shallow copy of an object, so we must override it if we want truly independent copies.

Assignment Operator Sequential Containers /** Assign the contents of one vector to another. @param other The vector to be assigned to this vector @return This vector with a copy of the other vector's contents */ Vector<T>& operator=(const vector<T>& other) { // Make a copy of the other vector. Vector<T> the_copy(other); // Swap contents of self with the copy. swap(the_copy); // Return self (the copy will be deleted) return *this; } Vector<int> v1(); Vector<int> v2(); v2 = v1; Upon return, the destructor for the temporary object (the_copy) is invoked automatically by the compiler, deleting the old data.

The Destructor Sequential Containers The purpose of the destructor is to undo what the constructor does. The constructor takes a block of uninitialized memory and sets it to a valid state, thus creating an object. When the destructor is finished, the object is in an invalid state and the memory it occupies can be reused for creating other objects. If this is not done, the program will have memory leaks. Each class has a default destructor, which effectively invokes the destructor for each data field. If the pointer references a dynamically allocated object (such as the array referenced by pointer the_data), the memory allocated to that object must be freed.

The std::swap Function Sequential Containers The standard version of std::swap() will work for most types that are assignable: Template <typename T> void std::swap(T& lhs,T& rhs) { T temp(lhs); lhs = rhs; rhs = temp; } What’s wrong with using std:swap to swap vectors? std::swap(vector1, vector2); Answer: the above uses the vector deep copy constructors and assignment operators.

The swap Function Sequential Containers By adding your own version of swap() for your class you can implement an optimized shallow version of std::swap() avoiding the need to make copy of the whole data area, potentially release old data areas or re-allocate the data area, as well as invoke the copy constructor for the contained type on each item copied. /** Exchanges the contents of this vector with another. */ void swap(Vector<T>& other) { std::swap(num_items, other.num_items); std::swap(current_capacity, other.current_capacity); std::swap(the_data, other.the_data); }