// Member function definitions // Constructor // // Dynamically allocate a new array of the given capacity. template Array::Array( std::size_t capacity ): capacity_{ capacity }, array_{ new T[capacity_]{} }, method_{ CONSTRUCTOR } { std::cout << "Constructor called: " << this << std::endl; } // Copy constructor // // Create a new array object that is a copy of the argument 'original': // The capacity is copied over, // a new array is dynamically allocated, and // the entries are copied over. template Array::Array( Array const &original ): capacity_{ original.capacity_ }, array_{ new T[capacity_] }, method_{ COPY_CONSTRUCTOR } { std::cout << "Copy constructor called: " << this << std::endl; // Copy over the values storied in the original's array for ( std::size_t k{0}; k < capacity_; ++k ) { array_[k] = original.array_[k]; } } // Move constructor // // Create a new array object that is a copy of the argument 'original' // under the assumption that the destructor will be called on the original // immediately after this call finishes. // The capacity and array are copied over, // the original is reset to an empty array: zero capacity and nullptr template Array::Array( Array &&original ): capacity_{ original.capacity_ }, array_{ original.array_ }, method_{ MOVE_CONSTRUCTOR } { std::cout << "Move constructor called: " << this << std::endl; // Reset the original original.capacity_ = 0; original.array_ = nullptr; } // Destructor // // Deallocate the memory for the array // - Note that calling delete [] on the 'nullptr' is // always acceptable and will never lead to an error. template Array::~Array() { std::cout << "Destructor called: " << this << std::endl; capacity_ = 0; delete []array_; } // Assignment operator // // If *this is on the left-hand side of an assignment operator // and 'rhs' is on the right-hand side, then: // We create a copy of the right-hand side, // swap all the member variables of this array and the copy, and // allow the destructor to be called on the copy with the original // values of 'this' to be called. template Array &Array::operator=( Array const &rhs ) { std::cout << "Assignment operator called: " << this << std::endl; Array copy{ rhs }; swap( copy ); method_ = ASSIGNMENT_OPERATOR; return *this; } // Move operator // // If *this is on the left-hand side of an assignment operator // and 'rhs' is on the right-hand side and the compiler has // determined that the right-hand side will have the destructor // called on it immediately after the assignment is called, // then this move operator is called instead of the assignment // operator, in which case: // All member variables are swapped, and // allow the destructor to be subsequently called on the 'rhs', // which will delete what was originally 'this' template Array &Array::operator=( Array &&rhs ) { std::cout << "Move operator called: " << this << std::endl; swap( rhs ); method_ = MOVE_OPERATOR; return *this; } // Constant indexing operator // // Return a constant reference to index 'n' of the array. template T const &Array::operator[]( std::size_t const n ) const { return array_[n]; } // Indexing operator // // Return a reference to index 'n' of the array. template T &Array::operator[]( std::size_t const n ) { return array_[n]; } // std::size_t capacity() const // // Return the capacity of this array. template std::size_t Array::capacity() const { return capacity_; } // Created method() const // // Return the method the current instance was created. template Created Array::method() const { return method_; } // void swap( Array &other ) // // Swap all the member variables with 'this' array // and the 'other' array. template void Array::swap( Array &other ) { std::swap( capacity_, other.capacity_ ); std::swap( array_, other.array_ ); std::swap( method_, other.method_ ); } // std::ostream operator<<( std::ostream &, Array const & ) // // Print the array using the format: // [*, *, *, *, *, ..., *] // where * are the entries of the array. template std::ostream &operator<<( std::ostream &out, Array const &array ) { out << "["; if ( array.capacity() != 0 ) { out << array[0]; for ( std::size_t k{1}; k < array.capacity(); ++k ) { out << ", " << array[k]; } } out << "]: "; switch ( array.method() ) { case CONSTRUCTOR: std::cout << "constructor"; break; case COPY_CONSTRUCTOR: std::cout << "copy constructor"; break; case MOVE_CONSTRUCTOR: std::cout << "move constructor"; break; case ASSIGNMENT_OPERATOR: std::cout << "assignment operator"; break; case MOVE_OPERATOR: std::cout << "move operator"; break; } return out; }