3
\$\begingroup\$

I haven't really programmed in C++ for about a year, and realised that I should get back into it, and tried my abilities out by remaking the STD vector class. However, my C++ is a bit rusty at the moment, and was wondering if I have made many mistakes in my implementation.

# ifndef VECTOR_H
# define VECTOR_H
# include <memory>

namespace test
    {
    template
        <class T,
    class A>
    class vector;

    template
        <class A>
        class vector_alloc_types
        {
    public:
        typedef typename A::value_type value_type;
        typedef typename A::size_type size_type;
        typedef typename A::reference reference;
        typedef typename A::const_reference const_reference;
        typedef typename A::pointer iterator;
        typedef typename A::const_pointer const_iterator;
        typedef typename A::const_pointer const_pointer;
        typedef A allocator_type;
        };

    template
        <class T,
        class A>
        class vector_base
        {
        friend class vector<T, A>;
    public:
        typedef typename A::pointer pointer;
        vector_base()
            {
            vm_begin = pointer();
            value_end = pointer();
            memory_end = pointer();
            }
    private:
        pointer vm_begin, value_end, memory_end;
        };

    template 
        <class T,
        class A = std::allocator<T> >
        class vector
            : public vector_alloc_types<A>,
            public vector_base<T, A>
        {
    public:
        typedef vector<T, A> my_T;
        typedef vector_base<T, A> my_base;

        vector()
            : my_base()
            {
            }

        vector(my_T const &rhs)
            {
            if (allocate(rhs.size()))
                {
                try
                    {
                    this->value_end = std::uninitialized_copy(rhs.vm_begin, rhs.value_end, this->vm_begin);
                    }
                catch (...)
                    {
                    kill();
                    throw;
                    }
                }
            }

        vector(pointer first, pointer last)
            : my_base()
            {
            if (allocate(std::distance(first, last)))
                {
                try
                    {
                    this->value_end = std::uninitialized_copy(first, last, this->vm_begin);
                    }
                catch (...)
                    {
                    kill();
                    throw;
                    }
                }
            }

        template<size_type sz>
        vector(T arr[sz])
            {
            if (allocate(sz))
                {
                try
                    {
                    this->value_end = std::uninitialized_copy_n(arr, sz, this->vm_begin);
                    }
                catch (...)
                    {
                    kill();
                    throw;
                    }
                }
            }

        vector(size_type sz)
            {
            if (allocate(sz))
                {
                try
                    {
                    this->value_end = std::uninitialized_fill_n(this->vm_begin, sz, T());
                    }
                catch (...)
                    {
                    kill();
                    throw;
                    }
                }
            }

        vector(size_type sz, T const &val)
            {
            if (allocate(sz))
                {
                try
                    {
                    this->value_end = std::uninitialized_fill_n(this->vm_begin, sz, val);
                    }
                catch (...)
                    {
                    kill();
                    throw;
                    }
                }
            }

        ~vector()
            {
            kill();
            }

        void operator=(my_T &rhs)
            {
            if (this != &rhs)
                {
                assign(rhs);
                }
            }

        template<unsigned sz>
        void operator=(T (&arr)[sz])
            {
            assign(&arr[0], &arr[sz]);
            }

        void clear()
            {
            wipe(this->vm_begin, this->value_end);
            }

        iterator begin()
            {
            return (this->vm_begin);
            }

        const_iterator cbegin() const
            {
            return ((const_iterator)this->vm_begin);
            }

        iterator end()
            {
            return (this->value_end);
            }

        const_iterator cend() const
            {
            return ((const_iterator)this->value_end);
            }

        void swap(my_T &rhs)
            {
            std::swap(this->vm_begin, rhs.vm_begin);
            std::swap(this->value_end, rhs.value_end);
            std::swap(this->memory_end, rhs.memory_end);
            }

        void shrink_to_fit()
            {
            if (has_spare_capacity())
                {
                my_T tmp(*this);
                swap(tmp);
                }
            }

        void erase(iterator iter)
            {
            pointer tmp;
            if (iter == (this->value_end - 1))
                {
                pop_back();
                }
            else if (iter == this->vm_begin)
                {
                pop_front();
                }
            else if (iterator_in_range(iter))
                {
                tmp = allocator_type().allocate(size() - 1);
                pointer tmp2 = std::uninitialized_copy(this->vm_begin, iter, tmp);
                tmp2 = std::uninitialized_copy((iter + 1), this->value_end, tmp2);
                assign(tmp, tmp2);
                }
            }

        void erase(iterator first, iterator last)
            {
            if (last == (this->value_end - 1))
                {
                while (last-- != first)
                    {
                    pop_back();
                    }
                pop_back();
                }
            else if (first == this->vm_begin)
                {
                while (first++ != last)
                    {
                    pop_front();
                    }
                pop_front();
                }
            else if (iterator_in_range(first) && iterator_in_range(last))
                {
                pointer tmp = allocator_type().allocate(size() - std::distance(first, last));
                pointer tmp2 = std::uninitialized_copy(this->vm_begin, first, tmp);
                tmp2 = std::uninitialized_copy((last + 1), this->value_end, tmp2);
                assign(tmp, tmp2);
                }
            }

        void insert(iterator iter, T const &val)
            {
            T v1 = val;
            if (iter == this->vm_begin)
                {
                push_front(v1);
                }
            else if (iter == (this->value_end - 1))
                {
                push_back(v1);
                }
            else if (iterator_in_range(iter))
                {
                allocator_type alloc;
                pointer tmp = alloc.allocate(realloc_size(size() + 1));
                pointer tmp2 = std::uninitialized_copy(this->vm_begin, iter, tmp);
                alloc.construct(tmp2++, v1);
                tmp2 = std::uninitialized_copy(iter, this->value_end, tmp2);
                assign(tmp, tmp2);
                }
            }

        void insert(iterator iter, int count, T const &val)
            {
            T v1 = val;
            if (iter == this->vm_begin)
                {
                while (count--)
                    {
                    push_front(v1);
                    }
                }
            else if (iter == (this->value_end - 1))
                {
                while (count--)
                    {
                    push_back(v1);
                    }
                }
            else if (iterator_in_range(iter))
                {
                allocator_type alloc;
                pointer tmp = alloc.allocate(realloc_size(size() + 1));
                pointer tmp2 = std::uninitialized_copy(this->vm_begin, iter, tmp);
                while (count--)
                    {
                    alloc.construct(tmp2++, v1);
                    }
                tmp2 = std::uninitialized_copy(iter, this->value_end, tmp2);
                assign(tmp, tmp2);
                }
            }

        void insert(iterator iter, iterator first, iterator last)
            {
            if (iter == this->vm_begin)
                {
                while (first != last)
                    {
                    push_front(*(first++));
                    }
                }
            else if (iter == (this->value_end - 1))
                {
                while (first != last)
                    {
                    push_back(*(first++));
                    }
                }
            else if (iterator_in_range(iter))
                {   
                allocator_type alloc;
                pointer tmp = alloc.allocate(realloc_size(size() + 1));
                pointer tmp2 = std::uninitialized_copy(this->vm_begin, iter, tmp);
                while (first != last)
                    {
                    alloc.construct(tmp2++, *(first++));
                    }
                tmp2 = std::uninitialized_copy(iter, this->value_end, tmp2);
                assign(tmp, tmp2);
                }
            }

        void push_back(T const &val)
            {
            allocator_type alloc;
            T v1 = val;
            if (has_spare_capacity())
                {
                this->value_end++;
                alloc.construct(this->value_end - 1, v1);
                }
            else if (reallocate(realloc_size(size() + 1)))
                {
                this->value_end++;
                alloc.construct(this->value_end - 1, v1);
                }
            }

        void pop_back()
            {
            pointer tmp = allocator_type().allocate(size() - 1);
            pointer tmp2 = std::uninitialized_copy(this->vm_begin, this->value_end - 1, tmp);
            assign(tmp, tmp2);
            }

        void push_front(T const &val)
            {
            allocator_type alloc;
            T v1 = val;
            vector tmp;
            tmp.push_back(v1);
            for (iterator it = this->vm_begin; it != this->value_end; ++it)
                {
                tmp.push_back(*it);
                }
            swap(tmp);
            }

        void pop_front()
            {
            pointer tmp = allocator_type().allocate(size() - 1);
            pointer tmp2 = std::uninitialized_copy(this->vm_begin + 1, this->value_end, tmp);
            assign(tmp, tmp2);
            }

        size_type size() const
            {
            return (this->value_end - this->vm_begin);
            }

        reference operator[](size_type pos)
            {
            return (*(this->vm_begin + pos));
            }

        const_reference operator[](size_type pos) const
            {
            return (*(this->vm_begin + pos));
            }

    private:
        bool allocate(size_type sz)
            {
            allocator_type alloc;
            if (alloc.max_size() > sz)
                {
                try
                    {
                    this->vm_begin = alloc.allocate(sz);
                    this->value_end = this->vm_begin;
                    this->memory_end = this->vm_begin + sz;
                    }
                catch (...)
                    {
                    kill();
                    throw;
                    }
                return (true);
                }
            return (false);
            }

        bool reallocate(size_type sz)
            {
            allocator_type alloc;
            if (alloc.max_size() > sz)
                {
                try
                    {
                    pointer nbegin, nvend, nmend;
                    nbegin = alloc.allocate(sz);
                    nmend = nbegin + sz;
                    nvend = std::uninitialized_copy(this->vm_begin, this->value_end, nbegin);
                    this->vm_begin = nbegin;
                    this->value_end = nvend;
                    this->memory_end = nmend;
                    }
                catch (...)
                    {
                    kill();
                    throw;
                    }
                return (true);
                }
            return (false);
            }

        size_type realloc_size(size_type sz) const
            {
            return ((allocator_type().max_size() > (sz * 1.5)) ? (sz * 1.5) : sz);
            }

        bool iterator_in_range(const_iterator iter) const
            {
            return (iter >= this->vm_begin && iter < this->value_end);
            }

        void assign(my_T &rhs)
            {
            assign(rhs.vm_begin, rhs.value_end);
            }

        void assign(pointer first, pointer last)
            {
            size_type sz = std::distance(first, last);
            if (sz > capacity())
                {
                if (reallocate(realloc_size(sz)))
                    {
                    wipe(this->vm_begin, this->value_end);
                    this->value_end = std::uninitialized_copy(first, last, this->vm_begin);
                    }
                }
            else
                {
                wipe(this->vm_begin, this->value_end);
                this->value_end = std::uninitialized_copy(first, last, this->vm_begin);
                }
            }

        void wipe(pointer ptr)
            {
            allocator_type().destroy(ptr);
            }

        void wipe(pointer first, pointer last)
            {
            allocator_type alloc;
            while (first != last)
                {
                alloc.destroy(first++);
                }
            }

        void wipe(pointer ptr, size_type dist)
            {
            allocator_type alloc;
            while (dist-- != 0)
                {
                alloc.destroy(ptr);
                }
            }

        void kill()
            {
            if (this->vm_begin != pointer())
                {
                wipe(this->vm_begin, this->value_end);
                allocator_type().deallocate(this->vm_begin, capacity());
                }
            }

        inline size_type capacity() const
            {
            return (this->memory_end - this->vm_begin);
            }

        inline size_type spare_capacity() const
            {
            return (this->memory_end - this->value_end);
            }

        bool has_spare_capacity() const
            {
            return (spare_capacity() > 0);
            }
        };
    }

# endif
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.