[C++系列] 53. vector深度剖析及模拟实现

0. std::vector


在这里插入图片描述

1. std::vector的核心框架接口的模拟实现bit::Vector

 // 
#include <iostream>
#include <algorithm>

#include <assert.h>
#include <string>
using namespace std;
 
// 注意这里namespace不需要进行缩进,因为其不影响代码结构
namespace bit
{
    template<class T>
    class Vector
    {
    public:
        // Vector的迭代器是一个原生指针
        typedef T* Iterator;
        typedef const T* ConstIterator;
 
        Iterator Begin() { return _start; }
        Iterator End() { return _finish; }
 
        ConstIterator CBegin() const { return _start; }
        ConstIterator CEnd() const { return _finish; }
 
        size_t Size() const { return _finish - _start; }
        size_t Capacity() const { return _endOfStorage - _start; }
 
        Vector()
            : _start(nullptr)
            , _finish(nullptr)
            , _endOfStorage(nullptr)
        {}
 
        Vector(int n, const T& value = T())		// 第二个参数设置为T的构造函数,会调用T的默认构造
            : _start(nullptr)
            , _finish(nullptr)
            , _endOfStorage(nullptr)
        {
            Reserve(n);
            while (n--)
            {
                PushBack(value);
            }
        }
 
        // 这里如果使用Iterator做迭代器,就会导致初始化的迭代器区间[first,last]只能是Vector的迭代器
        // 这里重新声明迭代器,迭代器区间[first,last]可以是任意容器的迭代器区间。
        template<class InputIterator>
        Vector(InputIterator first, InputIterator last)
        {
            Reserve(last - first);
            while (first != last)
            {
                PushBack(*first);
                ++first;
            }

        }
        Vector(const Vector<T>& v)
            : _start(nullptr)
            , _finish(nullptr)
            , _endOfStorage(nullptr)
        {
            Reserve(v.Capacity());
 
            Iterator it = Begin();
            ConstIterator vit = v.CBegin();
            while (vit != v.CEnd())
            {
                *it++ = *vit++;
            }
 
            _finish = _start + v.Size();
            _endOfStorage = _start + v.Capacity();
        }
 
        Vector<T>& operator= (Vector<T> v)
        {
            Swap(v);
            return *this;
        }
 
        ~Vector()
        {
            delete[] _start;
            _start = _finish = _endOfStorage = nullptr;
        }
 
        void Reserve(size_t n)
        {
            if (n > Capacity())
            {
                size_t size = Size();
                T* tmp = new T[n];
 
                // 这里直接使用memcpy是有问题的
                // 以后我们会用更好的方法解决
                //if (_start)
                //  memcpy(tmp, _start, sizeof(T)*size);
                if (_start)
                {
                    for (size_t i = 0; i < size; ++i)
                        tmp[i] = _start[i];
                }
 
                _start = tmp;
                _finish = _start + size;
                _endOfStorage = _start + n;
            }

        }
        void Resize(size_t n, const T& value = T())
        {
            // 1.如果n小于当前的size,则数据个数缩小到n
            if (n <= Size())
            {
                _finish = _start + n;
                return;
            }
 
            // 2.空间不够则增容
            if (n > Capacity())
            {
                Reserve(n);
            }
 
            // 3.将size扩大到n
            Iterator it = _finish;
            Iterator _finish = _start + n;
            while (it != _finish)
            {
                *it = value;
                ++it;
            }
        }
 
        void Swap(Vector<T>& v)
        {
            swap(_start, v._start);
            swap(_finish, v._finish);
            swap(_endOfStorage, v._endOfStorage);
        }
 
        void PushBack(const T& x)
        {
            Insert(End(), x);
        }
 
        void PopBack()
        {
            Erase(--End());
        }
 
        Iterator Insert(Iterator pos, const T& x)
        {
            assert(pos <= _finish);
 
            // 空间不够先进行增容
            if (_finish == _endOfStorage)
            {
                size_t size = Size();
                size_t newCapacity = Capacity() == 0 ? 1 : Capacity() * 2;

                Reserve(newCapacity);
                 // 如果发生了增容,需要重置pos
                pos = _start + size;
            }
 
            Iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                --end;
            }
 
            *pos = x;
            ++_finish;
            return pos;
        }
 
        // 返回删除数据的下一个数据
        // 方便解决:一边遍历一边删除的迭代器失效问题
        Iterator Erase(Iterator pos)
        {
            // 挪动数据进行删除
            Iterator begin = pos + 1;
            while (begin != _finish) {
                *(begin - 1) = *begin;
                ++begin;
            }
 
            --_finish;
 
            return pos;
        }
 
        T& operator[](size_t pos)
        {
            return _start[pos];
        }
    private:
        Iterator _start;        // 指向数据块的开始
        Iterator _finish;       // 指向有效数据的尾
        Iterator _endOfStorage; // 指向存储容量的尾
    };
}

2. 对bit::Vector进行严格的测试

// constructing vectors
void TestVector1()
{
    // constructors used in the same order as described above:
    bit::Vector<int> first;                                 // empty vector of ints

    bit::Vector<int> second(4, 100);                        // four ints with value 100
     bit::Vector<int> third(second.Begin(), second.End());   // iterating through second
    bit::Vector<int> fourth(third);                         // a copy of third
 
    // the iterator constructor can also be used to construct from arrays:
    int myints[] = { 16, 2, 77, 29 };
    bit::Vector<int> fifth(myints, myints + sizeof(myints) / sizeof(int));
 
    std::cout << "The contents of fifth are:";
    for (bit::Vector<int>::Iterator it = fifth.Begin(); it != fifth.End(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';
 
    // 测试T是string时,拷贝问题
    bit::Vector<string> strV;
    strV.PushBack("1111");
    strV.PushBack("2222");
    strV.PushBack("3333");
    strV.PushBack("4444");
    for (size_t i = 0; i < strV.Size(); ++i)
    {
        cout << strV[i] << " ";
    }
    cout << endl;
}
 
//vector iterator的使用
void PrintVector(const bit::Vector<int>& v)
{
    // 使用const迭代器进行遍历打印
    bit::Vector<int>::ConstIterator it = v.CBegin();
    while (it != v.CEnd())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}
 
void TestVector2()
{
    // 使用push_back插入4个数据
    bit::Vector<int> v;
    v.PushBack(1);
    v.PushBack(2);
    v.PushBack(3);
    v.PushBack(4);
 
    // 使用迭代器进行遍历打印
    bit::Vector<int>::Iterator it = v.Begin();
    while (it != v.End())
    {
        cout << *it << " ";

        ++it;
         }
    cout << endl;
 
    // 使用迭代器进行修改
    it = v.Begin();
    while (it != v.End())
    {
        *it *= 2;
        ++it;
    }
 
    PrintVector(v);
}
 
// capacity/vector::reserve/resize
void TestVector4()
{
    size_t sz;
    bit::Vector<int> foo;
    sz = foo.Capacity();
    std::cout << "making foo grow:\n";
    for (int i = 0; i < 100; ++i) {
        foo.PushBack(i);
        if (sz != foo.Capacity()) {
            sz = foo.Capacity();
            std::cout << "capacity changed: " << sz << '\n';
        }
    }
 
    // resverse
    bit::Vector<int> bar;
    sz = bar.Capacity();
    bar.Reserve(100);   // this is the only difference with foo above
    std::cout << "making bar grow:\n";
    for (int i = 0; i < 100; ++i) {
        bar.PushBack(i);
        if (sz != bar.Capacity()) {
            sz = bar.Capacity();
            std::cout << "capacity changed: " << sz << '\n';
        }
    }
 
    // resize
    bit::Vector<int> myvector;
    // set some initial content:
    for (int i = 1; i < 10; i++)
        myvector.PushBack(i);
 
    myvector.Resize(5);
    myvector.Resize(8, 100);
    myvector.Resize(12);
 

    std::cout << "myvector contains:";
    for (size_t i = 0; i < myvector.Size(); i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';
}
 
// find / insert / erase
void TestVector5()
{
    int a[] = { 1, 2, 3, 4 };
    bit::Vector<int> v(a, a + sizeof(a) / sizeof(int));
 
    // 使用find查找3所在位置的iterator
    bit::Vector<int>::Iterator pos = find(v.Begin(), v.End(), 3);
 
    // 在pos位置之前插入30
    v.Insert(pos, 30);
 
    bit::Vector<int>::Iterator it = v.Begin();
    while (it != v.End()) {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
 
    pos = find(v.Begin(), v.End(), 3);
    // 删除pos位置的数据
    v.Erase(pos);
 
    it = v.Begin();
    while (it != v.End()) {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}
 
// operator[]
void TestVector6()
{
    int a[] = { 1, 2, 3, 4 };
    bit::Vector<int> v(a, a + sizeof(a) / sizeof(int));
 
    // 通过[]读写第0个位置。
    v[0] = 10;
    cout << v[0] << endl;
 
    // 通过[i]的方式遍历vector
    for (size_t i = 0; i < v.Size(); ++i)
    {
        cout << v[i] << " ";
    }
    cout << endl;
    bit::Vector<int> swapv;
    swapv.Swap(v);
 
    cout << "v data:";
    for (size_t i = 0; i < v.Size(); ++i)
    {
        cout << v[i] << " ";
    }
    cout << endl;
 
    cout << "swapv data:";
    for (size_t i = 0; i < swapv.Size(); ++i)
    {
        cout << swapv[i] << " ";
    }
    cout << endl;
}
 
// iterator失效问题
void TestVector7()
{
    int a[] = { 1, 2, 3, 4 };
    bit::Vector<int> v(a, a + sizeof(a) / sizeof(int));
 
    // 使用find查找3所在位置的iterator
    bit::Vector<int>::Iterator pos = find(v.Begin(), v.End(), 3);
 
    // 删除pos位置的数据,导致pos迭代器失效。
    v.Erase(pos);
    cout << *pos << endl; // 此处会导致非法访问
 
    // 在pos位置插入数据,导致pos迭代器失效。
    // insert会导致迭代器失效,是因为insert可
    // 能会导致增容,增容后pos还指向原来的空间,而原来的空间已经释放了。
    pos = find(v.Begin(), v.End(), 3);
    v.Insert(pos, 30);
    cout << *pos << endl; // 此处会导致非法访问
 
    // 实现删除v中的所有偶数
    // 下面的程序会崩溃掉,如果是偶数,erase导致it失效
    // 对失效的迭代器进行++it,会导致程序崩溃
    bit::Vector<int>::Iterator it = v.Begin();
    while (it != v.End())
    {
        if (*it % 2 == 0)
            v.Erase(it);
 
        ++it;
    }
 
    // 以上程序要改成下面这样,erase会返回删除位置的下一个位置
    it = v.Begin();

    while (it != v.End()
    {
        if (*it % 2 == 0)
            it = v.Erase(it);
        else
            ++it;
    }
}
 
int main()
{
    //TestVector1();
    //TestVector2();
    //TestVector3();
    //TestVector4();
    //TestVector5();
    //TestVector6();
    //TestVector7();
 
    return 0;
}

本次模拟实现vector较为详细,将大大小小的vector内部接口均模拟实现了。一般在进行模拟实现某些数据结构时,只需要模拟实现出其较为有特点、有难点的几个重要步骤即可。通用接口在底层实现较为相同可以不必实现。

3. vector主要功能的简单模拟实现

#pragma once

namespace yl
{
	// 采用模板类进行模拟实现
	template <class T>
	class vector
	{
		T * m_start;
		T * m_finish;
		T * m_endOfStorage;
	public:
		typedef T * iterator;
		typedef const T * const_iterator;

		// vector第一种构造函数
		vector() :
			m_start(nullptr),
			m_finish(nullptr),
			m_endOfStorage(nullptr)
		{

		}

		// vector第二种构造函数的第二个参数传入其构造函数,当会调用默认构造函数进行初始化
		vector(int n, const T &val = T()) :
			m_start(nullptr),
			m_finish(nullptr),
			m_endOfStorage(nullptr)
		{
			reserve(n);

			for (int i = 0; i < n; i++)
			{
				m_start[i] = val;
			}
			m_finish = m_start + n;
		}

		// vector第三种构造函数使用迭代器进行初始化构造
		vector(T * start, T * end) :
			m_start(nullptr),
			m_finish(nullptr),
			m_endOfStorage(nullptr)
		{
			int _size = end - start;
			reserve(_size);

			for (int i = 0; i < _size; i++)
			{
				// memcpy在此不适用,因为memcpy完成的为浅拷贝
				// 若传入T 为string为对象时,会产生深拷贝,而深拷贝是对=进行重载完成的
				// 若=前后为对象时,会调用重载后的=完成对象的深拷贝
				m_start[i] = start[i];
			}
			m_finish = m_start + _size;		// 大小改变finish调整位置
		}

		iterator begin()
		{
			return m_start;
		}

		iterator end()
		{
			return m_finish;
		}

		size_t size()
		{
			return m_finish - m_start;
		}

		size_t capacity()
		{
			return m_endOfStorage - m_start;
		}

		T & operator [] (int i)
		{
			return m_start[i];
		}

		const T & operator [] (int i) const
		{
			return m_start[i];
		}

		void reserve(size_t _size)
		{
			int _capacity = capacity();

			if (_capacity < _size)
			{
				if (_capacity == 0)
				{
					_capacity = 1;
				}

				while (_capacity < _size)
				{
					_capacity *= 2;
				}
			}

			T * tmp = new T[_capacity];
			m_endOfStorage = tmp + _capacity;
			int oldsize = size();	// 如果第一次进入,size为0,需要记录size,m_finish被修改,size为finish-start已经改变,for循环内不可再采用size(),所以需要提前记录size值
			m_finish = tmp + oldsize;	// 此时finish及start指向同一片空间
			if (m_start != nullptr)
			{
				for (int i = 0; i < oldsize; i++)
				{
					tmp[i] = m_start[i];
				}
				// finish仍停留在老的空间中,如迭代器失效问题,此时应该更新finish
				// 但在if内,当第一次进入start为空时,finish及endOfStorage仍未敲定
				// m_finish = tmp + size();
				// m_endOfStorage = tmp + capacity;
				delete[] m_start;
			}
			m_start = tmp;
		}

		void resize(size_t _size, const T &val = T())
		{
			reserve(_size);

			for (int i = size(); i < _size; i++)
			{
				m_start[i] = val;
			}

			m_finish = m_start + _size;
		}

		// insert返回一个迭代器,防止迭代器失效
		// iterator写法一
		iterator insert(iterator pos, const T &val)		// 因为T在栈上操作,避免T是一个很大的类型,提高运行效率,而现在就是一个指针很快
		{
			int tmp = pos - m_start;
			reserve(size() + 1);	// m_start可能会在此改变,会导致pos改变
			pos = m_start + tmp;	// 避免pos失效,记录新pos

			int i;
			// 元素向后平移,注意最后面的最先移动不会被覆盖
			for (i = size() - 1; i >= pos - m_start; i--)
			{
				m_start[i + 1] = m_start[i];
			}

			*pos = val;		// 上述操作过后,该pos才能正常操作

			m_finish++;

			return pos;		// return真正的pos
		}

		// insert写法二:从pos位置开始,插入n个val值
		iterator insert(iterator pos, int n, const T &val)
		{
			int tmp = pos - m_start;
			reserve(size() + n);
			pos = m_start + tmp;

			int i;
			for (i = size() - 1; i >= pos - m_start; i--)
			{
				m_start[i + n] = m_start[i];
			}

			for (i = 0; i < n; i++)
			{
				pos[i] = val;
			}

			m_finish += n;

			return pos;
		}

		// insert写法三:在pos后插入start--end中的所有元素
		iterator insert(iterator pos, const T * start, const T * end)
		{
			int tmp = pos - m_start;
			int extsize = end - start;	// 需要记录,后面继续使用
			reserve(size() + extsize);
			pos = m_start + tmp;

			int i;
			for (i = size() - 1; i >= pos - m_start; i--)
			{
				m_start[i + extsize] = m_start[i];
			}

			for (i = 0; i < extsize; i++)
			{
				pos[i] = start[i];
			}

			m_finish += extsize;

			return pos;
		}

		iterator erase(iterator pos)
		{
			int i;

			for (i = pos - m_start; i < size() - 1; i++)
			{
				m_start[i] = m_start[i + 1];
			}
			m_finish--;

			return pos;		// 该写法pos不失效
		}

		iterator erase(iterator start, iterator end)
		{
			int i;
			int extsize = end - start;

			for (i = start - m_start; i < size() - extsize; i++)
			{
				m_start[i] = m_start[i + extsize];
			}
			m_finish -= extsize;

			return start;
		}

		void push_back(const T &val)
		{
			reserve(size() + 1);

			*m_finish = val;
			m_finish++;
		}

		void pop_back()
		{
			m_finish--;
		}
	};
};

针对vector的模拟实现,会有很多涉及到边界、迭代器失效的问题,一路坎坷,需要注意到的点有相应的注释,值得细细品味。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值