Author Topic: Six Fast Steps to a simple template class Vector ...  (Read 25341 times)

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Six Fast Steps to a simple template class Vector ...
« on: March 09, 2017, 09:05:50 AM »
Here is one more attempt, to demystify for beginning C++ students,  the steps to coding a simple Vector class ...



The first step will be just a Vector of int ...using a struct ... so all members are public by default.

Code: [Select]
// Vector_step1.cpp //  // 2017-03-09 //


#include <iostream>

using namespace std;

const unsigned INIT_CAP = 2;

struct Vector
{
    size_t len;
    size_t cap;
    int* ary;
   
    // default ctor ...
    Vector() :len(0), cap(0), ary(0) {}
   
    void push_back( int val );
    void enlarge();
   
    int operator [] ( size_t i ) const { return ary[i]; }
   
    // so can set new values in the vector //
    int& operator [] ( size_t i ) { return ary[i]; }
} ;


// definitions //

void Vector::push_back( int val )
{
    if( len == cap ) enlarge();
    ary[len] = val;
    ++ len;
}

void Vector::enlarge()
{
    if( cap ) cap += cap; // it gets doubled if had a value
    else cap = INIT_CAP;
   
    int* tmp = new int[cap]; // get enlarged memory //
   
    for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i]; // copy over //
   
    delete [] ary; // delete OLD aray memory //
   
    ary = tmp; // update ary pointer to point to new memory //
}




// a little test ... //
void print( const Vector& v )
{
    for( size_t i = 0; i < v.len; ++ i )
        cout << v[i] << ' ';
       
    cout << "\nThe len = " << v.len
         << ", the cap = " << v.cap << '\n';
}


int main()
{
    Vector v;
    v.push_back( 6 );
    v.push_back( 7 );
    v.push_back( 8 );
   
    print( v );
}
« Last Edit: March 11, 2017, 06:44:18 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to a simple template class Vector ...
« Reply #1 on: March 09, 2017, 09:07:43 AM »
In step 2 we ... (please see comments in program at top)


Code: [Select]
// Vector_step2.cpp //  // 2017-03-09 //


// Here, in step 2,
// we add "BIG THREE" needed when you use new memory
// 1) destructor ... (that calls a clear method)
// and 2) copy ctor
// and 3) overloaded assignment //


#include <iostream>

using namespace std;

const unsigned INIT_CAP = 2;

struct Vector
{
    size_t len;
    size_t cap;
    int* ary;
   
    // default ctor ...
    Vector() :len(0), cap(0), ary(0) {}
   
    // copy ctor ...
    Vector( const Vector& v )
    {
        len = v.len;
        cap = v.cap;
        ary = new int[ cap ];
        for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
    }
   
    // overloaded assignment ...
    Vector& operator = ( const Vector& v )
    {
        if( this != &v ) // if NOT same addresses //
        {
            delete [] ary; // since NOT same memory can now do this //

            len = v.len;
            cap = v.cap;
            ary = new int[ cap ];
            for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
        }
        return *this;
    }
   
    // destructor //
    ~Vector() { clear(); }
   
    void clear()
    {
        delete [] ary;
        cap = len = 0;
        ary = 0; // this fix clears up case of calling destructor after calling clear //
    }
   
    void push_back( int val );
    void enlarge();
   
    int operator [] ( size_t i ) const { return ary[i]; }
   
    // so can set new values in vector //
    int& operator [] ( size_t i ) { return ary[i]; }
} ;


// definitions //

void Vector::push_back( int val )
{
    if( len == cap ) enlarge();
    ary[len] = val;
    ++ len;
}

void Vector::enlarge()
{
    if( cap ) cap += cap; // it gets doubled if had a value
    else cap = INIT_CAP;
   
    int* tmp = new int[cap]; // get enlarged memory //
   
    for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i]; // copy over //
   
    delete [] ary; // delete OLD array memory //
   
    ary = tmp; // update ary pointer to point to new memory //
}




// a little test ... //
void print( const Vector& v )
{
    for( size_t i = 0; i < v.len; ++ i )
        cout << v[i] << ' ';
       
    cout << "\nThe len = " << v.len
         << ", the cap = " << v.cap << '\n';
}


int main()
{
    Vector v, w;
    v.push_back( 6 );
    v.push_back( 7 );
    v.push_back( 8 );
   
    print( v );
   
    Vector x(v); // calling copy ctor //
    cout << "After calling Vector x(v) ...\n";
    print( x );
   
    w = x; // call overloaded assignemnt //
    cout << "After calling w = x ...\n";
    print( w );
   
    w.clear();
    cout << "After calling w.clear() ...\n";
    print( w );
   
   
}
« Last Edit: March 11, 2017, 06:44:35 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to a simple template class Vector ...
« Reply #2 on: March 09, 2017, 09:10:04 AM »
In step 3 ... (again, please see comments at top of program)


Code: [Select]
// Vector_step3.cpp //  // 2017-03-10  //


// Here, in step 3, we do simple and fairly straight-foward
// update to a template class //



#include <iostream>

using namespace std;

const unsigned INIT_CAP = 2;

template< typename T >
class Vector
{
    size_t len;
    size_t cap;
    T* ary;
public:
    // default ctor ...
    Vector() :len(0), cap(0), ary(0) {}
   
    // copy ctor ...
    Vector( const Vector< T >& v )
    {
        len = v.len;
        cap = v.cap;
        ary = new int[ cap ];
        for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
    }
   
    // overloaded assignment ...
    Vector< T >& operator = ( const Vector< T >& v )
    {
        if( this != &v ) // if NOT same addresses //
        {
            delete [] ary; // since NOT same memory can now do this //

            len = v.len;
            cap = v.cap;
            ary = new int[ cap ];
            for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
        }
        return *this;
    }
   
    // destructor //
    ~Vector() { clear(); }
   
    void clear()
    {
        delete [] ary;
        cap = len = 0;
        ary = 0; // this fix clears up case of calling destructor after calling clear //
    }
   
    void push_back( const T& val );
    void enlarge();
   
    const T& operator [] ( size_t i ) const { return ary[i]; } // read only //
   
    // NOT const and returned by ref
    // so can set new values inside the vector //
    T& operator [] ( size_t i ) { return ary[i]; }
   
    size_t size() const { return len; }
    size_t capacity() const { return cap; }
} ;


// definitions //
template< typename T >
void Vector< T >::push_back( const T& val )
{
    if( len == cap ) enlarge();
    ary[len] = val;
    ++ len;
}
template< typename T >
void Vector< T >::enlarge()
{
    if( cap ) cap += cap; // it gets doubled if had a value
    else cap = INIT_CAP;
   
    T* tmp = new int[cap]; // get enlarged memory //
   
    for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i]; // copy over //
   
    delete [] ary; // delete OLD array memory //
   
    ary = tmp; // update ary pointer to point to new memory //
}


// a little external print function to aid testing input/output ... //
template< typename T >
void print( const Vector< T >& v )
{
    for( size_t i = 0; i < v.size(); ++ i )
        cout << v[i] << ' ';
       
    cout << "\nThe size = " << v.size()
         << ", the capacity = " << v.capacity() << '\n';
}



int main()
{
    Vector< int > v, w;
    v.push_back( 6 );
    v.push_back( 7 );
    v.push_back( 8 );
   
    print( v );
   
    Vector< int > x(v); // calling copy ctor //
    cout << "After calling Vector x(v) ...\n";
    print( x );
   
    w = x; // call overloaded assignemnt //
    cout << "After calling w = x ...\n";
    print( w );
   
    w.clear();
    cout << "After calling w.clear() ...\n";
    print( w );
}
« Last Edit: March 11, 2017, 07:05:36 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to a simple template class Vector ...
« Reply #3 on: March 09, 2017, 09:12:34 AM »
In step 4 ... (again please see comments at top of program)


Code: [Select]
// Vector_step4.cpp //  // 2017-03-10 //


// Here, in step 4, we add methods reserve and resize


#include <iostream>


const unsigned INIT_CAP = 2;

template< typename T >
class Vector
{
public:
    // default ctor ...
    Vector() :len(0), cap(0), ary(0) {}

    // copy ctor ...
    Vector( const Vector< T >& v )
    {
        len = v.len;
        cap = v.cap;
        ary = new int[ cap ];
        for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
    }

    // overloaded assignment ...
    Vector< T >& operator = ( const Vector< T >& v )
    {
        if( this != &v ) // if NOT same addresses //
        {
            delete [] ary; // since NOT same memory can now do this //

            len = v.len;
            cap = v.cap;
            ary = new int[ cap ];
            for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
        }
        return *this;
    }

    // destructor ...
    ~Vector() { clear(); }

    void clear()
    {
        delete [] ary;
        cap = len = 0;
        ary = 0; // this fix clears up case of calling destructor after calling clear //
    }

    void push_back( const T& val );

    void reserve( size_t );
    void resize( size_t );

    const T& operator [] ( size_t i ) const { return ary[i]; } // read only //

    // NOT const and returned by ref
    // so can set new values inside the vector //
    T& operator [] ( size_t i ) { return ary[i]; }


    size_t size() const { return len; }
    size_t capacity() const { return cap; }

private:
    size_t len;
    size_t cap;
    T* ary;

    void enlarge();
} ;


// definitions //
template< typename T >
void Vector< T >::push_back( const T& val )
{
    if( len == cap ) enlarge();
    ary[len] = val;
    ++ len;
}

template< typename T >
void Vector< T >::enlarge()
{
    if( cap ) cap += cap; // it gets doubled if had a value
    else cap = INIT_CAP;

    T* tmp = new int[cap]; // get enlarged memory //

    for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i]; // copy over //

    delete [] ary; // delete OLD array memory //

    ary = tmp; // update ary pointer to point to new memory ///
}

template < typename T >
void Vector< T >::reserve( size_t newCap )
{
    if( newCap > cap )
    {
        cap = newCap;
        T* tmp = new T[ cap ];
        for( size_t i = 0; i < len; ++i ) tmp[i] = ary[i];
        delete [] ary;
        ary = tmp; // update the base address of ary
    }
}

template < typename T >
void Vector< T >::resize( size_t newSize )
{
    if( newSize > len )
    {
        reserve( newSize );
        for( size_t i = len; i < cap; ++ i ) ary[i] = T();
        len = newSize;
    }
    else if( newSize < len )
        len = newSize;
}




// a little external print function to aid testing input/output ... //
template< typename T >
void print( const Vector< T >& v )
{
    using std::cout;
   
    for( size_t i = 0; i < v.size(); ++ i )
        cout << v[i] << ' ';
       
    cout << "\nThe size = " << v.size()
         << ", the capacity = " << v.capacity() << '\n';
}



int main()
{
    using std::cout;
   
    Vector< int > v, w;
    v.push_back( 6 );
    v.push_back( 7 );
    v.push_back( 8 );
   
    print( v );
   
    Vector< int > x(v); // calling copy ctor //
    cout << "After calling Vector x(v) ...\n";
    print( x );
   
    w = x; // call overloaded assignemnt //
    cout << "After calling w = x ...\n";
    print( w );
   
    w.reserve(10);
    w.push_back( 9 );
    cout << "After calling w.reserve(10) and w.push_back(9) ...\n";
    print( w );
   
    w.resize(6);
    cout << "After calling w.resize(6)...\n";
    print( w );

    w.resize(3);
    cout << "After calling w.resize(3)...\n";
    print( w );
   
    w.clear();
    cout << "After calling w.clear() ...\n";
    print( w );
}


A test to check-out a specific case of resize method ...


Code: [Select]
// Vector_4_test_resize.cpp //  // 2017-03-10 //


// Here, in step 4, we add specific test of resize //


#include <iostream>


const unsigned INIT_CAP = 2;

template< typename T >
class Vector
{
public:
    // default ctor ...
    Vector() :len(0), cap(0), ary(0) {}

    // copy ctor ...
    Vector( const Vector< T >& v )
    {
        len = v.len;
        cap = v.cap;
        ary = new int[ cap ];
        for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
    }

    // overloaded assignment ...
    Vector< T >& operator = ( const Vector< T >& v )
    {
        if( this != &v ) // if NOT same addresses //
        {
            delete [] ary; // since NOT same memory can now do this //

            len = v.len;
            cap = v.cap;
            ary = new int[ cap ];
            for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
        }
        return *this;
    }

    // destructor ...
    ~Vector() { clear(); }

    void clear()
    {
        delete [] ary;
        cap = len = 0;
        ary = 0; // this fix clears up case of calling destructor after calling clear //
    }

    void push_back( const T& val );

    void reserve( size_t );
    void resize( size_t );

    const T& operator [] ( size_t i ) const { return ary[i]; } // read only //

    // NOT const and returned by ref
    // so can set new values inside the vector //
    T& operator [] ( size_t i ) { return ary[i]; }


    size_t size() const { return len; }
    size_t capacity() const { return cap; }

private:
    size_t len;
    size_t cap;
    T* ary;

    void enlarge();
} ;


// definitions //
template< typename T >
void Vector< T >::push_back( const T& val )
{
    if( len == cap ) enlarge();
    ary[len] = val;
    ++ len;
}

template< typename T >
void Vector< T >::enlarge()
{
    if( cap ) cap += cap; // it gets doubled if had a value
    else cap = INIT_CAP;

    T* tmp = new int[cap]; // get enlarged memory //

    for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i]; // copy over //

    delete [] ary; // delete OLD array memory //

    ary = tmp; // update ary pointer to point to new memory ///
}

template < typename T >
void Vector< T >::reserve( size_t newCap )
{
    if( newCap > cap )
    {
        cap = newCap;
        T* tmp = new T[ cap ];
        for( size_t i = 0; i < len; ++i ) tmp[i] = ary[i];
        delete [] ary;
        ary = tmp; // update the base address of ary
    }
}

template < typename T >
void Vector< T >::resize( size_t newSize )
{
    if( newSize > len )
    {
        reserve( newSize );
        for( size_t i = len; i < cap; ++ i ) ary[i] = T();
        len = newSize;
    }
    else if( newSize < len )
        len = newSize;
}




// a little external print function to aid testing input/output ... //
template< typename T >
void print( const Vector< T >& v )
{
    using std::cout;

    for( size_t i = 0; i < v.size(); ++ i )
        cout << v[i] << ' ';

    cout << "\nThe size = " << v.size()
         << ", the capacity = " << v.capacity() << '\n';
}




int main()
{
    using std::cout;
   
    Vector< int > v, w;
    v.resize(10);
    print( v );
   
    v.push_back( 6 );
    v.push_back( 7 );
    v.push_back( 8 );
   
    print( v );
   
    Vector< int > x(v); // calling copy ctor //
    cout << "After calling Vector x(v) ...\n";
    print( x );
   
    w = x; // call overloaded assignemnt //
    cout << "After calling w = x ...\n";
    print( w );
   
    w.reserve(10);
    w.push_back( 9 );
    cout << "After calling w.reserve(10) and w.push_back(9) ...\n";
    print( w );
   
    w.resize(6);
    cout << "After calling w.resize(6)...\n";
    print( w );

    w.resize(3);
    cout << "After calling w.resize(3)...\n";
    print( w );
   
    w.clear();
    cout << "After calling w.clear() ...\n";
    print( w );
}
« Last Edit: March 11, 2017, 07:07:05 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to a simple template class Vector ...
« Reply #4 on: March 11, 2017, 06:43:54 AM »
Step 5 ... (again, please see comments in program ... and at the top ...)


Code: [Select]
// Vector_5_shrink_swap.cpp //  // 2017-03-10 //


// Here, in step 5, we add methods shrink and swap //


#include <iostream>


const unsigned INIT_CAP = 2;

template< typename T >
class Vector
{
public:
    // default ctor ...
    Vector() :len(0), cap(0), ary(0) {}

    // copy ctor ...
    Vector( const Vector< T >& v )
    {
        len = v.len;
        cap = v.cap;
        ary = new int[ cap ];
        for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
    }

    // overloaded assignment ...
    Vector< T >& operator = ( const Vector< T >& v )
    {
        if( this != &v ) // if NOT same addresses //
        {
            delete [] ary; // since NOT same memory can now do this //

            len = v.len;
            cap = v.cap;
            ary = new int[ cap ];
            for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
        }
        return *this;
    }

    // destructor ...
    ~Vector() { clear(); }

    void clear()
    {
        delete [] ary;
        cap = len = 0;
        ary = 0; // this fix clears up case of calling destructor after calling clear //
    }

    void push_back( const T& val );

    void reserve( size_t );
    void resize( size_t );
   
    void swap( Vector& vec );
    void shrink();

    const T& operator [] ( size_t i ) const { return ary[i]; } // read only //

    // NOT const and returned by ref
    // so can set new values inside the vector //
    T& operator [] ( size_t i ) { return ary[i]; }


    size_t size() const { return len; }
    size_t capacity() const { return cap; }

private:
    size_t len;
    size_t cap;
    T* ary;

    void enlarge();
} ;


// definitions //
template< typename T >
void Vector< T >::push_back( const T& val )
{
    if( len == cap ) enlarge();
    ary[len] = val;
    ++ len;
}

template< typename T >
void Vector< T >::enlarge()
{
    if( cap ) cap += cap; // it gets doubled if had a value
    else cap = INIT_CAP;

    T* tmp = new int[cap]; // get enlarged memory //

    for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i]; // copy over //

    delete [] ary; // delete OLD array memory //

    ary = tmp; // update ary pointer to point to new memory ///
}

template < typename T >
void Vector< T >::reserve( size_t newCap )
{
    if( newCap > cap )
    {
        cap = newCap;
        T* tmp = new T[ cap ];
        for( size_t i = 0; i < len; ++i ) tmp[i] = ary[i];
        delete [] ary;
        ary = tmp; // update the base address of ary
    }
}

template < typename T >
void Vector< T >::resize( size_t newSize )
{
    if( newSize > len )
    {
        reserve( newSize );
        for( size_t i = len; i < cap; ++ i ) ary[i] = T();
        len = newSize;
    }
    else if( newSize < len )
        len = newSize;
}

template< typename T >
void Vector< T >::swap( Vector& vec )
{
    T* aryTmp  = vec.ary; // save start address
    size_t lenTmp = vec.len;
    size_t capTmp = vec.cap;

    vec.ary = ary;
    vec.len = len;
    vec.cap = cap;

    ary = aryTmp;
    len = lenTmp;
    cap = capTmp;
}

template< typename T >
void Vector< T >::shrink()
{
    if( len < cap )
    {
        T* tmp = new T[ len ]; // get 'right-sized' memory //
        for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i];
        delete [] ary; // now can delete old memory //
        ary = tmp; // update with the address of the new memory //
        cap = len;
    }
}


// a little external print function to aid testing input/output ... //
template< typename T >
void print( const Vector< T >& v )
{
    using std::cout;
   
    for( size_t i = 0; i < v.size(); ++ i )
        cout << v[i] << ' ';

    cout << "\nThe size = " << v.size()
         << ", the capacity = " << v.capacity() << '\n';
}




int main()
{
    using std::cout;
   
    Vector< int > v, w;
    v.reserve(10);
    print( v );
   
    v.push_back( 6 );
    v.push_back( 7 );
    v.push_back( 8 );
   
    v.shrink();
    cout << "After v.reserve(10) and 3 push_backs and calling v.shrink() ...\n";
    print( v );
   
    Vector< int > x(v); // calling copy ctor //
    cout << "After calling Vector x(v) ...\n";
    print( x );
   
    w = x; // call overloaded assignemnt //
    cout << "After calling w = x ...\n";
    print( w );
   
    w.resize(10);
    w.push_back( 9 );
    cout << "After calling w.resize(10) and w.push_back(9) ...\n";
    print( w );
   
    w.resize(6);
    cout << "After calling w.resize(6)...\n";
    print( w );

    w.resize(3);
    cout << "After calling w.resize(3)...\n";
    print( w );
   
    w.clear();
    cout << "After calling w.clear() ...\n";
    print( w );
   
    w.swap(v);
    cout << "After calling w.swap(v) ... print( w ) is ...\n";
    print( w );
    cout << "And print( v ) is ...\n";
    print( v );
}
« Last Edit: March 11, 2017, 07:07:54 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: Six Fast Steps to a simple template class Vector ...
« Reply #5 on: March 11, 2017, 06:59:04 AM »
Here in step 6, we add iterators ... and separate out our Vector class into its own .h file with suitable guards ...


So, firstly, a little test program ...

Code: [Select]
// Vector_6_iterators.cpp //  // 2017-03-10 //


// Here, in step 6, we add iterators ...
// Also, we separate out our class Vector into its own .h file
// with suitable guards //


#include "Vector.h" // includes <iostream>



// a little external print function to aid testing input/output ... //
template< typename T >
void print( const Vector< T >& v )
{
    using std::cout;
    typename Vector< T >::const_iterator it;
    for( it = v.begin(); it != v.end(); ++ it )
        cout << *it << ' ';
       
    cout << "\nThe size = " << v.size()
         << ", the capacity = " << v.capacity() << '\n';
}



int main()
{
    using std::cout;
   
    Vector< int > v, w;
    v.reserve(10);
    print( v );
   
    v.push_back( 6 );
    v.push_back( 7 );
    v.push_back( 8 );
   
    v.shrink();
    cout << "After v.reserve(10) and 3 push_backs and calling v.shrink() ...\n";
    print( v );
   
    Vector< int > x(v); // calling copy ctor //
    cout << "After calling Vector x(v) ...\n";
    print( x );
   
    w = x; // call overloaded assignemnt //
    cout << "After calling w = x ...\n";
    print( w );
   
    w.resize(10);
    w.push_back( 9 );
    cout << "After calling w.resize(10) and w.push_back(9) ...\n";
    print( w );
   
    w.resize(6);
    cout << "After calling w.resize(6)...\n";
    print( w );

    w.resize(3);
    cout << "After calling w.resize(3)...\n";
    print( w );
   
    w.clear();
    cout << "After calling w.clear() ...\n";
    print( w );
   
    w.swap(v);
    cout << "After calling w.swap(v) ... print( w ) is ...\n";
    print( w );
    cout << "And print( v ) is ...\n";
    print( v );
}


And now, the file Vector.h needed above ...

Code: [Select]
// Vector.h //  // 2017-03-10 //

#ifndef VECTOR_2017_03_10_H
#define VECTOR_2017_03_10_H


#include <iostream>


const unsigned INIT_CAP = 2;

template< typename T >
class Vector
{
public:
    // default ctor ...
    Vector() :len(0), cap(0), ary(0) {}

    // copy ctor ...
    Vector( const Vector< T >& v )
    {
        len = v.len;
        cap = v.cap;
        ary = new int[ cap ];
        for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
    }

    // overloaded assignment ...
    Vector< T >& operator = ( const Vector< T >& v )
    {
        if( this != &v ) // if NOT same addresses //
        {
            delete [] ary; // since NOT same memory can now do this //

            len = v.len;
            cap = v.cap;
            ary = new int[ cap ];
            for( size_t i = 0; i < len; ++ i ) ary[i] = v.ary[i];
        }
        return *this;
    }

    // destructor ...
    ~Vector() { clear(); }

    void clear()
    {
        delete [] ary;
        cap = len = 0;
        ary = 0; // this fix clears up case of calling destructor after calling clear //
    }

    void push_back( const T& val );

    void reserve( size_t );
    void resize( size_t );

    void swap( Vector& );
    void shrink();


    const T& operator [] ( size_t i ) const { return ary[i]; } // read only //

    // NOT const and returned by ref
    // so can set new values inside the vector //
    T& operator [] ( size_t i ) { return ary[i]; }

    size_t size() const { return len; }
    size_t capacity() const { return cap; }
   
    typedef T* iterator;
    iterator begin() { return ary; }
    iterator end() { return ary+len; }

    typedef const T* const_iterator;
    const_iterator begin() const { return ary; }
    const_iterator end() const { return ary+len; }

private:
    size_t len;
    size_t cap;
    T* ary;

    void enlarge();
} ;


// definitions //
template< typename T >
void Vector< T >::push_back( const T& val )
{
    if( len == cap ) enlarge();
    ary[len] = val;
    ++ len;
}

template< typename T >
void Vector< T >::enlarge()
{
    if( cap ) cap += cap; // it gets doubled if had a value
    else cap = INIT_CAP;

    T* tmp = new int[cap]; // get enlarged memory //

    for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i]; // copy over //

    delete [] ary; // delete OLD array memory //

    ary = tmp; // update ary pointer to point to new memory ///
}

template < typename T >
void Vector< T >::reserve( size_t newCap )
{
    if( newCap > cap )
    {
        cap = newCap;
        T* tmp = new T[ cap ];
        for( size_t i = 0; i < len; ++i ) tmp[i] = ary[i];
        delete [] ary;
        ary = tmp; // update the base address of ary
    }
}

template < typename T >
void Vector< T >::resize( size_t newSize )
{
    if( newSize > len )
    {
        reserve( newSize );
        for( size_t i = len; i < cap; ++ i ) ary[i] = T();
        len = newSize;
    }
    else if( newSize < len )
        len = newSize;
}

template < typename T >
void Vector< T >::swap( Vector& vec )
{
    T* aryTmp  = vec.ary; // save start address
    size_t lenTmp = vec.len;
    size_t capTmp = vec.cap;

    vec.ary = ary;
    vec.len = len;
    vec.cap = cap;

    ary = aryTmp;
    len = lenTmp;
    cap = capTmp;
}

template < typename T >
void Vector< T >::shrink()
{
    if( len < cap )
    {
        T* tmp = new T[ len ]; // get 'right-sized' memory //
        for( size_t i = 0; i < len; ++ i ) tmp[i] = ary[i];
        delete [] ary; // now can delete old memory //
        ary = tmp; // update with the address of the new memory //
        cap = len;
    }
}

#endif


Also ... to get hints about how to add these methods

push
pop
back
empty

You can look here ...

class Vector ... and Stacks and Queues ...

http://developers-heaven.net/forum/index.php/topic,2622.0.html
« Last Edit: March 11, 2017, 07:29:49 AM by David »