Presentation is loading. Please wait.

Presentation is loading. Please wait.

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:

Similar presentations


Presentation on theme: "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:"— Presentation transcript:

1 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: copy constructor destructor overloaded assignment operator Do not rely on the default versions provided by the compiler! We will discuss these using the IntVector class as an example make sure you study the full implementation on the course website in detail the labs and assignments require similar designs

2 CPSC 252 The Big Three Page 2 Dynamic memory version of IntVector (I) class IntVector // Invariant: there are MAX_SIZE entries // indexed from 0 to MAX_SIZE-1 // entries not defined unless initialized { private: static const int MAX_SIZE=100; int capacity; int* value; // dynamic array of integer values Changes to the implementation to provide more flexibility array size ( capacity ) is now a variable, not a constant there is a default size value is a pointer to an array, not an array

3 CPSC 252 The Big Three Page 3 Constructor for dynamic memory IntVector We have to declare a constructor in IntVector.h IntVector( void ); // Post: vector has a capacity of MAX_SIZE integers We have to define the constructor in IntVector.cpp IntVector::IntVector( void ) // Post: vector has a capacity of MAX_SIZE integers { capacity = MAX_SIZE; value = new int[ MAX_SIZE ]; } None of the entries are defined, but memory is allocated

4 CPSC 252 The Big Three Page 4 Making copies of objects A copy constructor is invoked: implicitly when an object is a call-by-value parameter IntVector myVector; void myFunc( IntVector someVector ) { … } explicitly when we declare an object to be a copy IntVector otherVector( myVector ); If we do not implement a copy constructor for a class, the compiler implements one for us: it makes a shallow “bit-wise” copy of each data member this works for simple classes, with no dynamic memory

5 CPSC 252 The Big Three Page 5 What goes wrong with shallow copies This code does not do what you think it does! IntVector myVector; myVector.at(0) = 27; myVector.at(2) = -32; IntVector myOtherVector( myVector ); myOtherVector.at(2) = 12; cout << myVector.at(2) << “ “ << myOtherVector.at(2); The two objects share the same dynamic memory the capacities and the pointers have been copied myVector myOtherVector 27 12 value capacity value capacity 4 4

6 CPSC 252 The Big Three Page 6 Deep copies instead of shallow copies We have to do more work for a deep copy: don’t copy the pointers copy the objects to which the pointers are pointing instead then we get different data for each copy subsequent changes to one do not affect the other myVector myOtherVector 27 12 value capacity value capacity 4 27 -32 4

7 CPSC 252 The Big Three Page 7 Declaring a copy constructor: IntVector( const IntVector& otherVector ); // Post: this vector is a copy of otherVector Note that the copy constructor: has the same name as the class (like all constructors) it does not specify a return type the parameter is passed by reference (this is essential) call-by-value would require the copy constructor! the parameter is const Most compilers generate an error if you attempt to use a value parameter when declaring a copy constructor

8 CPSC 252 The Big Three Page 8 Defining (implementing) a copy constructor We make a deep copy by: allocating new memory for the copy copying the values from the old memory to the new IntVector::IntVector( const IntVector& otherVector ) // Post: this vector is a copy of otherVector { capacity = otherVector.capacity; value = new int[ capacity ]; for ( int i = 0; i < capacity; i++ ) { value[i] = otherVector.value[i]; }

9 CPSC 252 The Big Three Page 9 The copy() helper function For almost all classes that have a copy constructor we do the same operations for an assignment operator so we make a helper function that does the work void IntVector::copy( const IntVector& otherVector ) // Post: this vector is a copy of otherVector { capacity = otherVector.capacity; value = new int[ capacity ]; for ( int i = 0; i < capacity; i++ ) { value[i] = otherVector.value[i]; }

10 CPSC 252 The Big Three Page 10 Our final version of the copy constructor We simply use the copy() helper function to implement the copy constructor IntVector::IntVector( const IntVector& otherVector ) // Post: this vector is a copy of otherVector { copy( otherVector); } All of the classes that we will see will adopt this convention there is a copy helper function (always private) the copy constructor and the assignment operator invoke it

11 CPSC 252 The Big Three Page 11 Why we need destructors void myFunc( void ) { IntVector myVector(); // do whatever with the vector } The lifetime of myVector is only the function invocation memory is allocated when myFunc() is called memory must be released when myFunc() returns unfortunately, the memory is not automatically released we need to implement a destructor member function this will release the memory and whatever else needs doing

12 CPSC 252 The Big Three Page 12 Declaration of the destructor for the IntVector class ~IntVector( void ); // Post: memory allocated to vector has been released destructors do not have a return type the name of a destructor is always the name of the class preceded by a “~” (tilde) destructors perform any necessary “clean-up” operations we use a helper function (we will use it again later) IntVector::~IntVector( void ) // Post: memory allocated to vector has been released { clear(); }

13 CPSC 252 The Big Three Page 13 The clear() helper function For almost all classes that have a destructor: we need the same operations for an assignment operator so we make a helper function that does the work void IntVector::clear( void ) // Post: this vector has no dynamic memory allocated { delete [] value; } we use [] even though it is not necessary for integers it would be necessary if elements require destructors always private (just like the copy() helper function)

14 CPSC 252 The Big Three Page 14 Assignment statements for objects The assignment operator “=” can be used for all objects it can always be applied to any object it can be explicitly declared in the class declaration IntVector& operator=( const IntVector& otherVector ); // Post: this vector is a copy of otherVector otherwise the compiler will provide a default version the assignment operator is overloaded if we explicitly define it for a class the default version may be all we need but often it will not be so we have to provide our own

15 CPSC 252 The Big Three Page 15 Default component-wise assignment operator class CSample { public: CSample( void ); int getData( void ) const; void setData( int data ); private: int m_data; }; CSample sample1, sample2; sample1.setData( 7 ); sample2 = sample1; cout << sample2.getData(); The default version of the assignment operator uses the data members in sample1 to initialize the corresponding data members in sample2

16 CPSC 252 The Big Three Page 16 Syntax for the assignment operator The declaration of the overloaded assignment operator for our IntVector class looks like this: IntVector& operator=(const IntVector& otherVector ); // Post: this vector is a copy of otherVector the return value is a reference to an IntVector the IntVector parameter is passed by reference the parameter is const the return value is not const the return value is not void Why were these choices made?

17 CPSC 252 The Big Three Page 17 A reference is returned by the assignment operator IntVector & operator=( const IntVector& otherVector ); // Post: this vector is a copy of otherVector The “=” operator is a binary operator it has a left operand and a right operand vector2 = vector1; it returns a reference to the left operand often we do not make use of this, but we might vector3 = vector2 = vector1; the assignment operator is right associative: vector3 = ( vector2 = vector1 ); the result is the right operand for the second assignment

18 CPSC 252 The Big Three Page 18 A const reference is passed to the assignment operator IntVector& operator=( const IntVector & otherVector ); // Post: this vector is a copy of otherVector We don’t want to change the right operand so it is a const parameter We don’t want to make a copy of the right operand so it is a reference parameter We do want to change the left operand so the method is not const

19 CPSC 252 The Big Three Page 19 The keyword this this can be used in any member function (method) it provides a pointer to the object that invoked the method we can think of *this as being the object which operand invokes the assignment operator? vector2 = vector1; by convention, the left operand invokes the method the assignment above is equivalent to the method call vector2.operator=( vector1 );

20 CPSC 252 The Big Three Page 20 Definition (implementation) for assignment IntVector& IntVector::operator=( const IntVector& otherVector ) { if ( &otherVector != this ) { clear(); copy( otherVector ); } return *this; } special case for left=right (nothing to do) if-test assumes different objects have different addresses if not the same object “destroy” the left operand then make a copy of the right operand

21 CPSC 252 The Big Three Page 21 What else besides the “Big Three”? We have now seen all of the “big three” methods copy constructor destructor overloaded assignment operator There are some other methods that we usually need, but these are “easy” once we have the “big three” parameterized constructor default constructor accessor methods and mutator methods other helper methods (often a grow() method)

22 CPSC 252 The Big Three Page 22 Dynamic memory version of IntVector (review) class IntVector // Invariant: there are MAX_SIZE entries // indexed from 0 to MAX_SIZE-1 // entries not defined unless initialized { private: static const int MAX_SIZE=100; int capacity; int* value; // dynamic array of integer values public: // method declarations go here…

23 CPSC 252 The Big Three Page 23 Parameterized constructor We want to specify the size of an IntVector at run-time int capacity; cout > capacity; IntVector myVector( capacity ); We provide a constructor that accepts the capacity as a parameter IntVector( int numInts ); // Pre: numInts > 0 // Post: vector has capacity numInts integers

24 CPSC 252 The Big Three Page 24 Implementing a parameterized constructor IntVector::IntVector( int numInts ) // Pre: numInts > 0 // Post: vector has capacity numInts integers { capacity = numInts; value = new int[ numInts ]; } array is initialized to specified size the object remembers the size none of the elements are initialized

25 CPSC 252 The Big Three Page 25 Formal parameter names IntVector::IntVector( int capacity ) // Pre: capacity > 0 // Post: vector will hold capacity integers { capacity = capacity ; value = new int[ capacity ]; } OK if name does not match declaration name OK to be the same as a member variable name but the above code will not work, instead we need to say { this->capacity = capacity; value = new int[ capacity ]; }

26 CPSC 252 The Big Three Page 26 Default constructor The default constructor has no parameters IntVector( void ); // Post: vector has a capacity of MAX_SIZE integers We have already seen how to implement this IntVector::IntVector( void ) // Post: vector has a capacity of MAX_SIZE integers { capacity = MAX_SIZE; value = new int[ MAX_SIZE ]; }

27 CPSC 252 The Big Three Page 27 What classes get for free from the compiler The compiler provides the following “for free” a default component-wise assignment operator a default component-wise copy constructor The compiler may also provide a default default constructor only if no constructors are declared if you declare a parameterized constructor or if you declare a copy constructor then there is no default default constructor This is for your “own protection”

28 CPSC 252 The Big Three Page 28 What else do we need for the IntVector class? The change to using dynamic arrays means that: we had to write a default constructor and the “big three” but the public interface has not changed for existing methods so client code that is based on fixed-size arrays still works our new version is backwards compatible with the old We will have to look at the implementations of the other member function size() - modest changes at() - neither version needs any change print() - no changes required

29 CPSC 252 The Big Three Page 29 int IntVector::at( int index ) const // Post: if 0 <= index < size() the element // at index is returned, otherwise program aborted { return value[ index ]; } int& IntVector::at( int index ) // Post: if 0 <= index < size() the element // at index is returned, otherwise program aborted { return value[ index ]; } int IntVector::size( void ) const // Post: capacity of vector has been returned { return capacity ; // not always MAX_SIZE }

30 CPSC 252 The Big Three Page 30 How else might we extend the IntVector class? Possible extensions: indices can be negative as well as positive the array grows as needed when elements are added so client code that is based on fixed-size arrays still works our new version is backwards compatible with the old The version that is in /examples/IntVector has some of these On the next slide we will see when to grow the array

31 CPSC 252 The Big Three Page 31 Automatically expanding the array When we store into the array, we can expand the array (and copy existing values) if it is not big enough int& IntVector::at( int index ) // Post: if 0 <= index < size() the element // at index is returned, otherwise program aborted { if ( capacity <= index ) grow( index ) // allocate a larger array return value[ index ]; } The helper function grow() is similar to the copy() helper you ought to be able to write this one yourself! the IntSet class has a grow() helper function


Download ppt "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:"

Similar presentations


Ads by Google