Copy Constructors & Destructors 2-07-2013
Implementing a vector class local functions implicit constructors Destructors Copy Constructors Project #1: MiniMusicPlayer Quiz today 2/7/13 vectors and reading from a text file
template <class T> // version 1.0 class Vector { public: Vector(): buffer_(null), size_(0) { explicit Vector (int n); int size() const { return size_; T& operator[ ] (int i) { return buffer_[i]; const T& operator[ ] (int i) const { return buffer_[i]; void resize (int n); private: T* buffer_; // dynamic array containing the elements int size_; // current number of elements
template <class T> // version 1 class Vector { public: /* as in previous slide */ private: T* buffer_; int size_; /* create_new_buffer is a private method */ T* create_new_buffer ( int n ) const { return (n > 0)? new T[n] : NULL);
public: Vector (int n) : size_(n) { buffer_ = create_new_buffer(n); Problem: implicit conversions private: T* create_new_buffer ( int n ) const { return (n > 0)? new T[n] : NULL);
By default, a single argument constructor also defines an implicit conversion e.g. complex z = 2; // initialize z with complex(2) But this doesn t work for Vector e.g. Vector<string> v = 2; converts the 2 to a vector of size 2 Solution: explicit constructor prevents implicit conversions Note: Google C++ Style guidelines recommends that you always use the explicit keyword for any constructor of one argument (except for copy constructors)
public: explicit Vector (int n) : size_(n) { buffer_ = create_new_buffer(n); private: T* create_new_buffer ( int n ) const { return (n > 0)? new T[n] : NULL);
template <class T> void Vector<T>::resize ( int new_size ) { T* new_buffer = create_new_buffer(new_size); // copy elements to new buffer int min_size = (size_ < new_size)? size_ : new_size; for (int i = 0; i < min_size; i++) new_buffer[i] = buffer_[i]; // deallocate old buffer, if there is one if (buffer_!= NULL) delete[] buffer_; buffer_ = new_buffer; size_ = new_size;
Additional Vector methods Vector<T>::back() returns the last element in the vector Vector<T>:: push_back() adds an element to the end of the vector Vector<T>::pop_back() removes the last element from the vector
You can access the last element of a vector with v[ v.size() 1 ] Will add another method to simplify this v.back( )
template<class T> T& Vector<T>::back( ) { return buffer_ [ size_ - 1 ]; template<class T> const T& Vector<T>::back( ) const { return buffer_ [ size_ - 1 ] ;
template<class T> void Vector<T>::push_back( const T& new_element ) { resize( size( ) + 1 ); back( ) = new_element; template<class T> void Vector<T>::pop_back( ) { resize( size( ) 1 );
The current implementation of Vector has a memory leak! void f ( ) { Vector<string> v1( 3 ); v1.push_back( here ); v1.push_back( and ); v1.push_back( there ); allocates a dynamic array of size 3 When the function f returns, v1 is destroyed, but the array remains
template <class T> // version 1.0 class Vector { public: Vector( ): buffer_(null), size_(0) { explicit Vector (int n); ~Vector( ) { if (buffer_!= NULL) delete[ ] buffer_; A class can have any number of constructors, but only one destructor
FAQ 30.02 What are the Big Three? Destructor Copy Constructor Assignment operator A class that dynamically allocates memory or other resources should implement the big three. FAQ 30.06 What is the law of the Big Three? If a class needs any of the Big Three, it needs them all.
A copy constructor creates a copy of an existing object There are three circumstances when a copy constructor is called: (1) When an object is created and initialized to be a copy of another one (2) When an object is passed by value to a function (3) When a function returns an object
Vector<int> v1; v1.push_back(24); v1.push_back(15); v1.push_back(36); Vector<int> v2(v1); // v2 is a copy of v1 Can also write this as: Vector<int> v2 = v1;
void f ( Vector<int> a ) { int main( ) { Vector<string> v; f( v ); // the argument a is a copy of v...
Vector<int> g ( ) { Vector<int> t; return t; int main( ) { Vector<string> v; v = g( ) ; // the vector returned from g is // copied into v...
class Item { public: Item(); Item(const Item& x); class Chart { public: Chart(); // no explicit copy constructor private: Item z;
consider: Chart c1; Chart c2 = c1; // initialization by copy By default, the copy of a class object is a copy of each data member, so if Chart does not have an explicit copy constructor, the compiler will synthesize one which copy constructs each data member of Chart (that is, it calls the copy constructor for Item) This is called memberwise copy construction, otherwise known as a shallow copy.
class Item { int main() { public: Chart c1; Item( ); Chart c2 = c1; Item(const Item& x); /* compiler-synthesized copy class Chart { constructor for Chart is called public: and it calls Item::Item(const Chart( ); Item&) automatically */ // no explicit copy constructor private: Item z;
Destroying & Copying Vectors Maciel: Chapter 7, sections 7.4