cse 143 class vector interface
play

CSE 143 Class Vector: Interface class Vector { public: Dynamic - PDF document

CSE 143 Class Vector: Interface class Vector { public: Dynamic Memory In Classes Vector ( ); bool isEmpty( ); [Chapter 4, p 156-157] int length ( ); void vectorInsert (int newPosition, Item newItem); Item vectorDelete (int position);


  1. CSE 143 Class Vector: Interface class Vector { public: Dynamic Memory In Classes Vector ( ); bool isEmpty( ); [Chapter 4, p 156-157] int length ( ); void vectorInsert (int newPosition, Item newItem); Item vectorDelete (int position); Item vectorRetrieve (int position); ... } 07/13/01 07/13/01 N-1 N-2 Many Ways to Implement Vector Implementation • Version 1: With Fixed length arrays class Vector { public: • Very efficient to access individual elements // constructors and other methods, as before • Limited in size, flexibility private: • Version 2: With a linked list (later) Item *items; // items[0..capacity] is space allocated for • Very flexible in size // this vector int size; // items are stored in Items[0..size-1] • Inefficient to access individual elements int capacity; //current maximum array size Have to chase pointers down the list • Here’s a third way: // might need additional private helper functions • Use an array (for efficient access) • Make the array itself "dynamic" }; Able to grow as needed 07/13/01 07/13/01 N-3 N-4 Draw the picture! Vector Constructor Vector::Vector() { // set up private variables capacity = DEFAULT_CAPACITY; size = 0; // allocate memory items = new Item[capacity]; // what goes here? } Except for this, the public methods can be the same as for the fixed array implementation. Exception: insert needs to ensure there is room to add a new item. 07/13/01 07/13/01 N-5 N-6 CSE 143 N

  2. Useful Private Functions ensureCapacity( ) class Vector { // ensure that Vector can hold at least n elements void Vector::ensureCapacity(int n) { public: // return if existing capacity is ok // constructors and other methods if (capacity >= n) private: return; // data members here... // out of space: double capacity // ensure the Vector can hold at least n elements int newCapacity = capacity * 2; void ensureCapacity(int n); if (newCapacity < n) newCapacity = n; // set size of the Vector to n elements void growArray(int n); // grow the array growArray(newCapacity); }; } 07/13/01 07/13/01 N-7 N-8 growArray( ) Now insert is easy! // Set size of vector to newCapicity // insert newItem at newPosition in Vector void Vector::vectorInsert(int newPosition, Item newItem) { void Vector::growArray(int newCapacity) { // make room Item *newItems = new Item[newCapacity]; ensureCapacity(size+1); assert(newItems != NULL); // shift data over for (int i = 0; i < size; ++i) for (int i=size; i > newPosition; --i) newItems[i] = items[i]; items[i] = items[i-1]; // store the item ... items[newPosition] = newItem; items = newItems; size++; capacity = newCapacity; } } Have we forgotten anything? 07/13/01 07/13/01 N-9 N-10 Issues with Dynamic Memory Innocence Destroyed (I) • Using dynamic memory in classes raises issues // assume Item == int • Familiar dangers: Vector v1, v2; • Dangling pointers, Uninitialized pointers, Memory leaks, v1.vectorInsert(0, 30); etc. v1.vectorInsert(1, 4); • Some new complications v2 = v1; • Many of them arise when objects are copied v2.vectorDelete(0); Copied automatically when passed as parameters, etc. Copied explicitly by programmer • Other dangers when objects are deleted • //Draw the picture and weep! Explicitly deleted, or just go out of scope • C++ has some special features to help the situation 07/13/01 07/13/01 N-11 N-12 CSE 143 N

  3. Innocence Destroyed (II) After v2=v1, Before v2.vectorDelete void add42 (Vector v) { //add 42 to front of vector v1 v.vectorInsert(0, 42); } items 30 4 size 2 //code in main capacity 5 Vector v1; v1.vectorInsert(0, 0); v2 items add42(v1); size How does v2.vectorDelete • v1 passed by value, so no harm done -- right?? 2 change the picture? • Draw the picture and weep! capacity 5 07/13/01 07/13/01 N-13 N-14 After v1.insert(0,0) After v.insert(0, 42);... in main: in add42: v1 v items items size size 1 0 2 42 0 capacity 5 capacity 5 back in main... call add42: v1 v items items size 1 size 1 capacity 5 capacity 5 07/13/01 07/13/01 N-15 N-16 Innocence Destroyed (III) Local variable goes away... void MyFunction () { tempVector (in MyFunction) Vector tempVector; //local variable items 0 42 -3 4 // build a temporary vector for whatever reason size 4 ... capacity 5 } • When a function exits now back in main... • local variables are automatically destroyed • so having a local Vector is no problem -- right? 0 42 -3 4 • Draw the picture and weep! 07/13/01 07/13/01 N-17 N-18 CSE 143 N

  4. The Culprit: "Shallow Copy" More copy problems • For structs and classes, all and only the • The problem with deep vs. shallow copying can member variables are copied also appear in these contexts: • When there’s dynamic memory, that’s not • Initialization in a variable declaration: enough SomeClass f1; SomeClass f2 = f1; • Example: the items pointer value is copied, so the • Passing a copy of an actual to a formal parameter ( pass- copy points to the same place by-value ) • Can lead to surprises and bugs • Returning an instance as the value of a function: • Solution: need a concept of "deep copy" return someIntVector; Why? because a function returns a new, temporary object • By default, C++ performs such initializations using shallow copy semantics. 07/13/01 07/13/01 N-19 N-20 Needed: Deep Copy "Deep copy" • A "deep copy" should make a complete new copy, • A deep copy makes a completely independent including new dynamic memory copy, by allocating more dynamic memory • A way to make the deep copy happen original automatically when appropriate items 0 42 -3 4 • Vector v1 = v2; size 4 • v1 = v2; • func1(v1); capacity 5 • return v1; (deep) copy • PS: this won’t solve the problem of cleaning up dynamic memory used by local variables items 0 42 -3 4 • We’ll get back to that size 4 capacity 5 07/13/01 07/13/01 N-21 N-22 Deep copy for Vector Making It Automatic • Initialize the new vector to empty. • Problem with copyVector: must be called explicitly • For each element in the vector • We need it to happen automatically in certain cases • add it to the new vector • Could be a client function • Solution: C++ allows a "Copy Constructor" • void copyVector (Vector &orig, Vector &newVec); • Will be called automatically in certain cases where an object must be initialized from an existing object • use member functions like length, retrieve, insert, etc. • Compiler recognizes it as a constructor with a • Could be a public or private member function particular parameter list: • void Vector::copy (Vector &orig); • classname ( classname &) • copies from orig to current vector • or classname (const classname &) • use private data directly 07/13/01 07/13/01 N-23 N-24 CSE 143 N

  5. Copy Constructor for listClass Inside the Copy Constructor class Vector { • It’s just a function, it can do anything! public: • But... what you normally write is a deep copy Vector ( ); • For our Vector copy constructor: Vector(Vector &); • could call a previously defined copyVector function ... • could build the new copy directly } • If you don’t define your own copy constructor, the • Compiler recognizes this as a copy constructor compiler generates a default copy constructor • Will call automatically when • Does a shallow copy • passing arguments by value • initializing variable with = in a variable declaration • copying a return value 07/13/01 07/13/01 N-25 N-26 Look at the code: Technicalities of ’=’ Vector MyVector = YourVector; Vector::Vector(Vector &other) { copy(other); } is NOT THE SAME AS // private member function: replace this Vector // with a deep copy of other Vector MyVector; void Vector::copy(Vector &other) { MyVector = YourVector; // set up private variables capacity = other.capacity; • The difference in technical terms: size = other.size; • in the first case, the object is being created // allocate memory items = new Item[capacity]; • in the second case, the object already exists assert(items != NULL); • To handle the latter case, we have to define an // copy data "overloaded assignment operator" for (int i = 0; i < size; ++i) items[i] = other.items[i]; • Syntax: Vector & Vector::operator = (Vector &other); } • The code for this function could (should) perform a deep copy. 07/13/01 07/13/01 N-27 N-28 Detour: this Overloaded operator = • A reserved word in C++ Four important steps: • Means “a pointer to the current object” 1. Test for same object: • Like a hidden parameter to member functions • if (&other != this) { /* copy code */ } • int Vector::length( Vector *this Vector *this ) { ... } Vector *this 2. Delete old dynamically allocated data • only exists in member functions! • call cleanup() function if you have one, or • Can use like any other pointer • directly: delete [] items; • Vector *vp = this; 3. Copy new data • if (vp == this) ... • copy() if you have one • return this->size; • this->capacity = this->capacity * 2; 4. Return a reference to the current object: • this->length( ) • return *this; 07/13/01 07/13/01 N-29 N-30 CSE 143 N

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend