5
\$\begingroup\$

I decided to implement the std::vector class in C++, and was wondering if I had done everything correctly. When I mean 'correctly', I mean that the code is efficiently written and done properly. I have tested all the functions using various tests and they seem to output correct results.

I have not included every function in the std class: the main ones that I have not included are assign/insert and I have not implemented a reverse_iterator, although I have made my own iterator and const_iterator class.

# include <memory>
// I included the below two headers for my tests
# include <iostream>
# include <string>

namespace mynamespace
{
template <typename T, typename A>
class vector;

template<typename Vec_T>
class vector_const_iterator;

template<typename Vec_T>
class vector_iterator
    {
public:
    typedef vector_iterator<Vec_T> this_t;
    typedef typename Vec_T::value_type T;

    friend Vec_T;

    vector_iterator(T *ptr_, Vec_T const &cont)
        : container(cont),
        ptr(ptr_)
        {
        }

    vector_iterator(this_t const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    vector_iterator(vector_const_iterator<Vec_T> const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    ~vector_iterator()
        {
        }

    bool operator!=(this_t const &rhs) const
        {
        return (ptr != rhs.ptr);
        }

    bool operator!=(T *ptr_) const
        {
        return (ptr != ptr_);
        }

    bool operator==(this_t const &rhs) const
        {
        return (ptr == rhs.ptr);
        }

    bool operator==(T *ptr_) const
        {
        return (ptr == ptr_);
        }

    bool operator>(this_t const &rhs) const
        {
        return (ptr > rhs.ptr);
        }

    bool operator>(T *ptr_) const
        {
        return (ptr > ptr_);
        }

    bool operator>=(this_t const &rhs) const
        {
        return (ptr >= rhs.ptr);
        }

    bool operator>=(T *ptr_) const
        {
        return (ptr >= ptr_);
        }

    bool operator<(this_t const &rhs) const
        {
        return (ptr < rhs.ptr);
        }

    bool operator<(T *ptr_) const
        {
        return (ptr < ptr_);
        }

    bool operator<=(this_t const &rhs) const
        {
        return (ptr <= rhs.ptr);
        }

    bool operator<=(T *ptr_) const
        {
        return (ptr <= ptr_);
        }

    T &operator*()
        {
        if (is_valid_ptr())
            {
            return (*ptr);
            }
        throw std::exception("vector_iterator: pointer out of safe range when dereferencing (operator*)");
        }

    T *operator->()
        {
        if (is_valid_ptr())
            {
            return (ptr);
            }
        throw std::exception("vector_iterator: pointer out of safe range when dereferencing (operator->)");
        }

    this_t operator++(int)
        {
        this_t holder(*this);
        ++(*this);
        return (holder);
        }

    this_t &operator++()
        {
        ++ptr;
        return (*this);
        }

    this_t operator+=(unsigned offset)
        {
        ptr += offset;
        return (*this);
        }

    this_t &operator-=(unsigned offset)
        {
        ptr -= offset;
        return (*this);
        }

    T &operator[](unsigned offset) const
        {
        this_t holder(*this);
        holder.ptr += offset;
        if (holder.is_valid_ptr())
            {
            return (*(ptr + offset));
            }
        throw std::exception("vector_iterator: pointer out of safe range when dereferencing (operator[])");
        }

    this_t &operator=(this_t const &rhs)
        {
        ptr = rhs.ptr;
        return (*this);
        }

    this_t operator+(unsigned offset)
        {
        return (this_t(ptr + offset, container));
        }

    this_t operator-(unsigned offset)
        {
        return (this_t(ptr - offset, container));
        }

    unsigned operator-(this_t const &rhs)
        {
        return (ptr - rhs.ptr);
        }

    this_t operator--(int)
        {
        this_t holder(*this);
        --(*this);
        return (holder);
        }

    this_t &operator--()
        {
        --ptr;
        return (*this);
        }

    operator vector_const_iterator<Vec_T>()
        {
        return (vector_const_iterator<Vec_T>(ptr, container));
        }

private:
    Vec_T const &container;
    T *ptr;

    bool is_valid_ptr() const
        {
        return (ptr >= container.mem_start
            && ptr < container.seq_end);
        }

    bool is_valid_ptr2() const
        {
        return (ptr >= container.mem_start
            && ptr <= container.seq_end);
        }
    };

template<typename Vec_T>
class vector_const_iterator
    {
public:
    typedef vector_const_iterator<Vec_T> this_t;
    typedef typename Vec_T::value_type T;

    friend Vec_T;

    vector_const_iterator(T *ptr_, Vec_T const &cont)
        : container(cont),
        ptr(ptr_)
        {
        }

    vector_const_iterator(this_t const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    vector_const_iterator(vector_iterator<Vec_T> const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    ~vector_const_iterator()
        {
        }

    bool operator!=(this_t const &rhs) const
        {
        return (ptr != rhs.ptr);
        }

    bool operator!=(T *ptr_) const
        {
        return (ptr != ptr_);
        }

    bool operator==(this_t const &rhs) const
        {
        return (ptr == rhs.ptr);
        }

    bool operator==(T *ptr_) const
        {
        return (ptr == ptr_);
        }

    bool operator>(this_t const &rhs) const
        {
        return (ptr > rhs.ptr);
        }

    bool operator>(T *ptr_) const
        {
        return (ptr > ptr_);
        }

    bool operator>=(this_t const &rhs) const
        {
        return (ptr >= rhs.ptr);
        }

    bool operator>=(T *ptr_) const
        {
        return (ptr >= ptr_);
        }

    bool operator<(this_t const &rhs) const
        {
        return (ptr < rhs.ptr);
        }

    bool operator<(T *ptr_) const
        {
        return (ptr < ptr_);
        }

    bool operator<=(this_t const &rhs) const
        {
        return (ptr <= rhs.ptr);
        }

    bool operator<=(T *ptr_) const
        {
        return (ptr <= ptr_);
        }

    T const &operator*()
        {
        if (is_valid_ptr())
            {
            return (*ptr);
            }
        throw std::exception("vector_const_iterator: pointer out of safe range when dereferencing (operator*)");
        }

    T const *operator->()
        {
        if (is_valid_ptr())
            {
            return (ptr);
            }
        throw std::exception("vector_const_iterator: pointer out of safe range when dereferencing (operator->)");
        }

    this_t operator++(int)
        {
        this_t holder(*this);
        ++(*this);
        return (holder);
        }

    this_t &operator++()
        {
        ++ptr;
        return (*this);
        }

    this_t operator+=(unsigned offset)
        {
        ptr += offset;
        return (*this);
        }

    this_t &operator-=(unsigned offset)
        {
        ptr -= offset;
        return (*this);
        }

    T &operator[](unsigned offset) const
        {
        this_t holder(*this);
        holder.ptr += offset;
        if (holder.is_valid_ptr())
            {
            return (*(ptr + offset));
            }
        throw std::exception("vector_const_iterator: pointer out of safe range when dereferencing (operator[])");
        }

    this_t &operator=(this_t const &rhs)
        {
        ptr = rhs.ptr;
        return (*this);
        }

    this_t operator+(unsigned offset)
        {
        return (this_t(ptr + offset, container));
        }

    this_t operator-(unsigned offset)
        {
        return (this_t(ptr - offset, container));
        }

    unsigned operator-(this_t const &rhs)
        {
        return (ptr - rhs.ptr);
        }

    this_t operator--(int)
        {
        this_t holder(*this);
        --(*this);
        return (holder);
        }

    this_t &operator--()
        {
        --ptr;
        return (*this);
        }

    operator vector_iterator<Vec_T>()
        {
        return (vector_iterator<Vec_T>(ptr, container));
        }

private:
    Vec_T const &container;
    T *ptr;

    bool is_valid_ptr() const
        {
        return (ptr >= container.mem_start
            && ptr < container.seq_end);
        }

    bool is_valid_ptr2() const
        {
        return (ptr >= container.mem_start
            && ptr <= container.seq_end);
        }
    };

template<typename Vec_T>
class vector_const_reverse_iterator;

template<typename Vec_T>
class vector_reverse_iterator
    {
public:
    typedef vector_reverse_iterator<Vec_T> this_t;
    typedef typename Vec_T::value_type T;

    friend Vec_T;

    vector_reverse_iterator(T *ptr_, Vec_T const &cont)
        : container(cont),
        ptr(ptr_)
        {
        }

    vector_reverse_iterator(this_t const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    vector_reverse_iterator(vector_const_reverse_iterator<Vec_T> const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    ~vector_reverse_iterator()
        {
        }

    bool operator!=(this_t const &rhs) const
        {
        return (ptr != rhs.ptr);
        }

    bool operator!=(T *ptr_) const
        {
        return (ptr != ptr_);
        }

    bool operator==(this_t const &rhs) const
        {
        return (ptr == rhs.ptr);
        }

    bool operator==(T *ptr_) const
        {
        return (ptr == ptr_);
        }

    bool operator>(this_t const &rhs) const
        {
        return (ptr < rhs.ptr);
        }

    bool operator>(T *ptr_) const
        {
        return (ptr < ptr_);
        }

    bool operator>=(this_t const &rhs) const
        {
        return (ptr <= rhs.ptr);
        }

    bool operator>=(T *ptr_) const
        {
        return (ptr <= ptr_);
        }

    bool operator<(this_t const &rhs) const
        {
        return (ptr > rhs.ptr);
        }

    bool operator<(T *ptr_) const
        {
        return (ptr > ptr_);
        }

    bool operator<=(this_t const &rhs) const
        {
        return (ptr >= rhs.ptr);
        }

    bool operator<=(T *ptr_) const
        {
        return (ptr >= ptr_);
        }

    T &operator*()
        {
        if (is_valid_ptr())
            {
            return (*ptr);
            }
        throw std::exception("vector_reverse_iterator: pointer out of safe range when dereferencing (operator*)");
        }

    T *operator->()
        {
        if (is_valid_ptr())
            {
            return (ptr);
            }
        throw std::exception("vector_reverse_iterator: pointer out of safe range when dereferencing (operator->)");
        }

    this_t operator++(int)
        {
        this_t holder(*this);
        --(*this);
        return (holder);
        }

    this_t &operator++()
        {
        --ptr;
        return (*this);
        }

    this_t operator+=(unsigned offset)
        {
        ptr -= offset;
        return (*this);
        }

    this_t &operator-=(unsigned offset)
        {
        ptr += offset;
        return (*this);
        }

    T &operator[](unsigned offset) const
        {
        this_t holder(*this);
        holder.ptr -= offset;
        if (holder.is_valid_ptr())
            {
            return (*(ptr - offset));
            }
        throw std::exception("vector_reverse_iterator: pointer out of safe range when dereferencing (operator[])");
        }

    this_t &operator=(this_t const &rhs)
        {
        ptr = rhs.ptr;
        return (*this);
        }

    this_t operator+(unsigned offset)
        {
        return (this_t(ptr + offset, container));
        }

    this_t operator-(unsigned offset)
        {
        return (this_t(ptr - offset, container));
        }

    unsigned operator-(this_t const &rhs)
        {
        return (rhs.ptr - ptr);
        }

    this_t operator--(int)
        {
        this_t holder(*this);
        ++(*this);
        return (holder);
        }

    this_t &operator--()
        {
        --ptr;
        return (*this);
        }

    operator vector_const_reverse_iterator<Vec_T>()
        {
        return (vector_const_reverse_iterator<Vec_T>(ptr, container));
        }

private:
    Vec_T const &container;
    T *ptr;

    bool is_valid_ptr() const
        {
        return (ptr >= container.mem_start
            && ptr < container.seq_end);
        }

    bool is_valid_ptr2() const
        {
        return (ptr >= (container.mem_start - 1)
            && ptr < container.seq_end);
        }
    };

template<typename Vec_T>
class vector_const_reverse_iterator
    {
public:
    typedef vector_const_reverse_iterator<Vec_T> this_t;
    typedef typename Vec_T::value_type T;

    friend Vec_T;

    vector_const_reverse_iterator(T *ptr_, Vec_T const &cont)
        : container(cont),
        ptr(ptr_)
        {
        }

    vector_const_reverse_iterator(this_t const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    vector_const_reverse_iterator(vector_reverse_iterator<Vec_T> const &rhs)
        : container(rhs.container),
        ptr(rhs.ptr)
        {
        }

    ~vector_const_reverse_iterator()
        {
        }

    bool operator!=(this_t const &rhs) const
        {
        return (ptr != rhs.ptr);
        }

    bool operator!=(T *ptr_) const
        {
        return (ptr != ptr_);
        }

    bool operator==(this_t const &rhs) const
        {
        return (ptr == rhs.ptr);
        }

    bool operator==(T *ptr_) const
        {
        return (ptr == ptr_);
        }

    bool operator>(this_t const &rhs) const
        {
        return (ptr < rhs.ptr);
        }

    bool operator>(T *ptr_) const
        {
        return (ptr < ptr_);
        }

    bool operator>=(this_t const &rhs) const
        {
        return (ptr <= rhs.ptr);
        }

    bool operator>=(T *ptr_) const
        {
        return (ptr <= ptr_);
        }

    bool operator<(this_t const &rhs) const
        {
        return (ptr > rhs.ptr);
        }

    bool operator<(T *ptr_) const
        {
        return (ptr > ptr_);
        }

    bool operator<=(this_t const &rhs) const
        {
        return (ptr >= rhs.ptr);
        }

    bool operator<=(T *ptr_) const
        {
        return (ptr >= ptr_);
        }

    T const &operator*()
        {
        if (is_valid_ptr())
            {
            return (*ptr);
            }
        throw std::exception("vector_const_reverse_iterator: pointer out of safe range when dereferencing (operator*)");
        }

    T const *operator->()
        {
        if (is_valid_ptr())
            {
            return (ptr);
            }
        throw std::exception("vector_const_reverse_iterator: pointer out of safe range when dereferencing (operator->)");
        }

    this_t operator++(int)
        {
        this_t holder(*this);
        --(*this);
        return (holder);
        }

    this_t &operator++()
        {
        --ptr;
        return (*this);
        }

    this_t operator+=(unsigned offset)
        {
        ptr -= offset;
        return (*this);
        }

    this_t &operator-=(unsigned offset)
        {
        ptr += offset;
        return (*this);
        }

    T &operator[](unsigned offset) const
        {
        this_t holder(*this);
        holder.ptr -= offset;
        if (holder.is_valid_ptr())
            {
            return (*(ptr - offset));
            }
        throw std::exception("vector_const_reverse_iterator: pointer out of safe range when dereferencing (operator[])");
        }

    this_t &operator=(this_t const &rhs)
        {
        ptr = rhs.ptr;
        return (*this);
        }

    this_t operator+(unsigned offset)
        {
        return (this_t(ptr - offset, container));
        }

    this_t operator-(unsigned offset)
        {
        return (this_t(ptr + offset, container));
        }

    unsigned operator-(this_t const &rhs)
        {
        return (rhs.ptr - ptr);
        }

    this_t operator--(int)
        {
        this_t holder(*this);
        ++(*this);
        return (holder);
        }

    this_t &operator--()
        {
        ++ptr;
        return (*this);
        }

    operator vector_reverse_iterator<Vec_T>()
        {
        return (vector_reverse_iterator<Vec_T>(ptr, container));
        }

private:
    Vec_T const &container;
    T *ptr;

    bool is_valid_ptr() const
        {
        return (ptr >= container.mem_start
            && ptr < container.seq_end);
        }

    bool is_valid_ptr2() const
        {
        return (ptr >= (container.mem_start - 1)
            && ptr < container.seq_end);
        }
    };

template <typename T, typename A = std::allocator<T> >
class vector
    {
public:
    typedef T value_type;
    typedef value_type &reference;
    typedef value_type const &const_reference;
    typedef value_type *pointer;
    typedef value_type const *const_pointer;
    typedef vector<T, A> this_t;
    typedef A allocator_t;
    typedef vector_iterator<this_t> iterator;
    typedef vector_const_iterator<this_t> const_iterator;
    typedef vector_reverse_iterator<this_t> reverse_iterator;
    typedef vector_const_reverse_iterator<this_t> const_reverse_iterator;

    friend class iterator;
    friend class const_iterator;
    friend class reverse_iterator;
    friend class const_reverse_iterator;

    vector()
        : mem_start(pointer()),
        seq_end(pointer()),
        mem_end(pointer())
        {
        }

    vector(this_t const &rhs)
        : mem_start(pointer()),
        seq_end(pointer()),
        mem_end(pointer())
        {
        assign(rhs);
        }

    vector(unsigned count, value_type const &val = value_type())
        : mem_start(pointer()),
        seq_end(pointer()),
        mem_end(pointer())
        {
        assign(count, val);
        }

    template<unsigned N>
    vector(value_type (&arr)[N])
        : mem_start(pointer()),
        seq_end(pointer()),
        mem_end(pointer())
        {
        assign(&arr[0], &arr[N]);
        }

    vector(pointer start, pointer end)
        : mem_start(pointer()),
        seq_end(pointer()),
        mem_end(pointer())
        {
        assign(start, end);
        }

    ~vector()
        {
        wipe_all();
        }

    template<unsigned N>
    void assign(value_type (&arr)[N])
        {
        assign(&arr[0], &arr[N]);
        }

    void assign(unsigned count, value_type const &val = value_type())
        {
        value_type v = val;
        if (points_to(&val))
            {
            v = val;
            }
        if (is_clean() || size() == 0)
            {
            allocate(count);
            }
        else if (count < capacity())
            {
            wipe_values();
            }
        else
            {
            reallocate(count);
            wipe_values();
            }
            seq_end = std::uninitialized_fill_n(mem_start, count, v);
        }

    void assign(pointer first, pointer last)
        {
        if (!points_to(first) && !points_to(last))
            {
            if (is_clean() || size() == 0)
                {
                allocate(last - first);
                }
            else if ((last - first) < capacity())
                {
                wipe_values();
                }
            else
                {
                reallocate((last - first));
                wipe_values();
                }
                seq_end = std::uninitialized_copy(first, last, mem_start);
            }
        }

    void assign(this_t const &rhs)
        {
        if (&rhs != this)
            {
            if (rhs.size() <= capacity())
                {
                wipe_values();
                }
            else if (is_clean() || size() == 0)
                {
                allocate(rhs.size());
                }
            else
                {   
                reallocate(rhs.size());
                wipe_values();
                }
            seq_end = std::uninitialized_copy(rhs.mem_start, rhs.seq_end, mem_start);
            }
        }

    this_t &operator=(this_t const &rhs)
        {
        assign(rhs);
        return (*this);
        }

    void swap(this_t &rhs)
        {
        std::swap(mem_start, rhs.mem_start);
        std::swap(seq_end, rhs.seq_end);
        std::swap(mem_end, rhs.mem_end);
        }

    void push_front(const_reference value)
        {
        T to_push = value;
        if (points_to(&value))
            {
            to_push = value;
            }
        this_t holder;
        holder.allocate(capacity() + 1);
        holder.push_back(to_push);
        holder.seq_end = std::uninitialized_copy(mem_start, seq_end, holder.mem_start + 1);
        swap(holder);
        }

    void push_back(const_reference value)
        {
        T to_push = value;
        if (is_clean() || size() == 0)
            {
            allocate(2);
            }
        else if ((size() + 1) > capacity())
            {
            reallocate(capacity() * 1.5);
            }
        else if (points_to(&value))
            {
            to_push = value;
            }
        allocator_t al;
        al.construct(seq_end++, to_push);
        }

    void pop_front()
        {
        if ((mem_start + 1) == seq_end)
            {
            this_t holder;
            holder.allocate(capacity());
            swap(holder);
            }
        else
            {
            this_t holder(mem_start + 1, seq_end);
            holder.reallocate(capacity());
            swap(holder);
            }
        }

    void pop_back()
        {
        allocator_t al;
        al.destroy(seq_end - 1);
        --seq_end;
        }

    void insert(iterator position, const value_type &val)
        {
        if (position.is_valid_ptr2())
            {
            if (position == seq_end)
                {
                push_back(val);
                }
            else if (position = mem_start)
                {
                push_front(val);
                }
            else
                {
                this_t holder;
                holder.allocate(capacity() + 1);
                holder.seq_end = std::uninitialized_copy(mem_start, position, holder.mem_start);
                holder.push_back(val);
                holder.seq_end = std::uninitialized_copy(position, seq_end, holder.seq_end);
                swap(holder);
                }
            }
        }

    void insert(iterator position, unsigned count, const value_type &val)
        {
        if (position.is_valid_ptr2())
            {
            for (int i = 0; i < size(); ++i)
                {
                if (position == seq_end)
                    {
                    while (count--)
                        {
                        push_back(val);
                        }
                    }
                else if(position == mem_start)
                    {
                    while (count--)
                        {
                        push_front(val);
                        }
                    }
                else
                    {
                    this_t holder;
                    holder.allocate(capacity() + count);
                    holder.seq_end = std::uninitialized_copy(mem_start, position, holder.mem_start);
                    holder.seq_end = std::uninitialized_fill_n(holder.seq_end, count, val);
                    holder.seq_end = std::uninitialized_copy(position, seq_end, holder.seq_end);
                    swap(holder);
                    }   
                }
            }
        }

    void insert(iterator position, iterator first, iterator last)
        {
        if (first.is_valid_ptr() && last.is_valid_ptr2())
            {
            if (first == last)
                {
                insert(position, *first);
                }
            else if (first == begin())
                {
                while (last != first)
                    {
                    push_front(last--);
                    }
                }
            else if (last == end())
                {
                while (first != last)
                    {
                    push_back(first++);
                    }
                }
            else
                {
                this_t holder;
                allocator_t al;
                if (holder.allocate(capacity() + (last - first)))
                    {
                    holder.seq_end = std::uninitialized_copy(mem_start, first.ptr, holder.mem_start);
                    while (first != last)
                        {
                        push_back(first++);
                        }
                    holder.seq_end = std::uninitialized_copy((last.ptr + 1), seq_end, holder.seq_end);
                    swap(holder);
                    }
                }
            }
        }

    void erase(iterator it)
        {
        if (it.is_valid_ptr())
            {
            if (it == mem_start)
                {
                pop_front();
                }
            else if (it == (seq_end - 1))
                {
                pop_back();
                }
            else
                {
                erase(it, it + 1);
                }
            }   
        }

    void erase(iterator start, iterator end_)
        {
        if (start.is_valid_ptr() && end_.is_valid_ptr2())
            {
            if (start == end_)
                {
                erase(start);
                }
            else if (start == begin())
                {
                while (end_-- != start)
                    {
                    pop_front();
                    }
                }
            else if (end_ == end())
                {
                while (end_-- != start)
                    {
                    pop_back();
                    }
                }
            else
                {
                this_t holder;
                allocator_t al;
                if (holder.allocate(capacity()))
                    {
                    holder.seq_end = std::uninitialized_copy(mem_start, start.ptr, holder.mem_start);
                    holder.seq_end = std::uninitialized_copy(end_.ptr, seq_end, holder.seq_end);
                    swap(holder);
                    }
                }
            }
        }

    void clear()
        {
        wipe_values();
        seq_end = mem_start;
        }

    void reserve(unsigned count)
        {
        if (count < capacity())
            {
            reallocate(count);
            }
        }

    reference operator[](unsigned offset)
        {
        return (*(mem_start + offset));
        }

    const_reference operator[](unsigned offset) const
        {
        return (*(mem_start + offset));
        }

    reference at(unsigned offset)
        {
        return (*(begin() + offset));
        }

    const_reference at(unsigned offset) const
        {
        return (*(begin() + offset));
        }

    reference front()
        {
        return (*(begin()));
        }

    const_reference front() const
        {
        return (*(cbegin()));
        }

    reference back()
        {
        return (*(end() - 1));
        }

    const_reference back() const
        {
        return (*(cend() - 1));
        }

    iterator begin()
        {
        return (iterator(mem_start, (*this)));
        }

    iterator end()
        {
        return (iterator(seq_end, (*this)));
        }

    const_iterator cbegin()
        {
        return (const_iterator(mem_start, (*this)));
        }

    const_iterator cend()
        {
        return (const_iterator(seq_end, (*this)));
        }

    reverse_iterator rbegin()
        {
        return (reverse_iterator(seq_end - 1, (*this)));
        }

    reverse_iterator rend()
        {
        return (reverse_iterator(mem_start - 1, (*this)));
        }

    const_reverse_iterator crbegin() const
        {
        return (const_reverse_iterator(seq_end - 1, (*this)));
        }

    const_reverse_iterator crend() const
        {
        return (const_reverse_iterator(mem_start - 1, (*this)));
        }

    iterator make_iterator(unsigned offset)
        {
        return (iterator(mem_start + offset, (*this)));
        }

    iterator make_iterator(reference position)
        {
        return (iterator(&position, (*this)));
        }

    const_iterator make_const_iterator(unsigned offset)
        {
        return (const_iterator(mem_start + offset, (*this)));
        }

    const_iterator make_const_iterator(reference position)
        {
        return (const_iterator(&position, (*this)));
        }

    void shrink_to_fit()
        {
        if (size() < capacity())
            {
            this_t holder = *this;
            swap(holder);
            }
        }

    unsigned size() const
        {
        return (seq_end - mem_start);
        }

    unsigned capacity() const
        {
        return (mem_end - mem_start);
        }

    bool empty() const
        {
        return (is_clean() || size() == 0);
        }

private:
    pointer mem_start, seq_end, mem_end;

    bool points_to(const_pointer ptr)
        {
        return (ptr >= mem_start && ptr <= seq_end);
        }

    bool allocate(unsigned size)
        {
        mem_start = pointer();
        seq_end = pointer();
        mem_end = pointer();
        allocator_t al;
        if (size < al.max_size())
            {
            mem_start = al.allocate(size);
            seq_end = mem_start;
            mem_end = mem_start + size;
            return (true);
            }
        return (false);
        }

    void reallocate(unsigned size)
        {
        allocator_t al;
        while (size == capacity())
            {
            size *= 2;
            }
        pointer new_memstart = al.allocate(size), new_seqend;
        new_seqend = std::uninitialized_copy(mem_start, seq_end, new_memstart);
        wipe_all();
        if (allocate(size))
            {
            seq_end = std::uninitialized_copy(new_memstart, new_seqend, mem_start);
            }
        }

    void wipe_values()
        {
        allocator_t al;
        if (!is_clean())
            {
            unsigned sz = size(), sz2 = size();
            while (sz-- != 0)
                {
                al.destroy(mem_start++);
                }
            mem_start -= sz2;
            }
        }

    void wipe_all()
        {
        if (!is_clean())
            {
            allocator_t al;
            wipe_values();
            unsigned cp = capacity();
            al.deallocate(mem_start, cp);
            }
        }

    bool is_clean() const
        {
        return (mem_start == pointer() &&
            seq_end == pointer() && mem_end == pointer());
        }
    };
}
\$\endgroup\$
1
  • \$\begingroup\$ reverse_iterator is specified to be reverse_iterator<iterator>. You are not allowed to roll out your own vector_reverse_iterator. \$\endgroup\$
    – L. F.
    Commented Jun 16, 2019 at 1:26

1 Answer 1

6
\$\begingroup\$

There's a rather large amount of code here, so I'm just going to make some comments as I find things.

void reallocate(unsigned size)
    {
    allocator_t al;
    while (size == capacity())
        {
        size *= 2;
        }

This looks like it might be a bug, did you mean to do while size <= capacity instead?

Additionally you probably want to check for overflow here too otherwise bad things will happen, make sure size*2 actually fits into an unsigned.

Also I might be biased slightly because I've been using Python a lot lately but I particularly dislike declaring variables like this:

pointer new_memstart = al.allocate(size), new_seqend;

Putting one variable per line I find much nicer.

One thing I notice here is duplicated code for the operators in a few places. Specifically I'd implement as many operators as possible in terms of other operators. For example:

bool operator==(this_t const &rhs) const
    {
    return (ptr == rhs.ptr);
    }

bool operator!=(this_t const &rhs) const
    {
    return (ptr != rhs.ptr);
    }

would become:

bool operator==(this_t const &rhs) const
    {
    return (ptr == rhs.ptr);
    }

bool operator!=(this_t const &rhs) const
    {
    return !operator==(rhs);
    }

You can do this for a bunch of the operators, which will help the maintainability of the code.

Now while the following is not exactly duplicated:

bool is_valid_ptr() const
    {
    return (ptr >= container.mem_start
        && ptr < container.seq_end);
    }

bool is_valid_ptr2() const
    {
    return (ptr >= container.mem_start
        && ptr <= container.seq_end);
    }

It looks very similar. A comment explaining why these 2 seemingly similar functions exist and when to which version would be good. While most of the code seems self-explanatory the places that are less obvious would greatly benefit from some documentation.

EDIT as per the comments:

I might be inclined to rewrite the pointer validity check functions as follows:

/** Check if the pointer is a valid location in the container */
bool is_valid_ptr() const
    {
    return (ptr >= container.mem_start
        && ptr < container.seq_end);
    }

/** Check if the pointer is a valid location in the container or is the end pointer */
bool is_valid_ptr_or_end() const
    {
    return (is_valid_ptr() || ptr == container.seq_end);
    }

This change makes it a lot clearer to the reader what is going on here.

\$\endgroup\$
2
  • \$\begingroup\$ Ok.. So, on my code on my laptop, it is infact size <= capacity(); I must have copied it wrong. is_valid_ptr is to test if iterators point within the sequence (as in they point to somewhere with a value which is why the first iterators are tested for this). is_valid_ptr2 is used to test if they point within the sequence or point to the end of the sequence [undefinded], but it is only used on end iterators when their value is not copied in the function \$\endgroup\$
    – Joe
    Commented Jun 22, 2015 at 5:29
  • \$\begingroup\$ I edited in light of that comment, that information would be really good somewhere in the code itself. \$\endgroup\$
    – shuttle87
    Commented Jun 23, 2015 at 3:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.