STL标准模板库——vector模拟实现

一,关于vector

vector的数据安排以及操作方式与array数组非常相似,两者的唯一差别在于对空间运用的灵活性。array是静态空间,一旦配置了就不能改变,这也是为什么定义数组时[]里只能给常量不能给变量;vector是动态空间,随着元素的假如,它的内部机制会自行扩充空间以容纳新元素,对于内存的合理利用与运用的灵活性会有很大的帮助。

vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率,而且所谓扩充空间,是“配置新空间/数据移动/释放旧空间”的大工程,时间成本很高。

二,vector模拟实现

2.1 基本框架和迭代器实现

#include<iostream>
using namespace std;

template<class T>
class vecctor
{
public:
	typedef T* iterator;//定义在这里就可以访问类成员变量了
	typedef const T* const_iterator;//const是提供给const对象用的
	const_iterator begin()const//end和begin要变成const迭代器,不然就可读可写了
	{
		return _start;
	}
	const_iterator end()const
	{
		return _finish;
	}
	iterator begin()
	{
		return _start;
	}
	iterator end()
	{
		return _finish;
	}
private:
	iterator _start;              //表示目前使用空间的头
	iterator _finish;             //表示目前使用空间的尾
	iterator _end_of_storage;     //表示目前可用空间的尾
};

2.2 构造和析构

vector()
    : _start(nullptr)
    , _finish(nullptr)
    , _end_of_storage(nullptr)
{}

vector(int n, const T& val = T())
    :_start(nullptr)
    , _finish(nullptr)
    , _end_of_storage(nullptr)
{
    reserve(n);
    for (size_t i = 0; i < n; ++i)
    {
        push_back(val);
    }
}

template<class InputIterator>
vector(InputIterator first, InputIterator last)//迭代器区间拷贝构造
    :_start(nullptr)
    , _finish(nullptr)
    , _end_of_storage(nullptr)
{
    while (first != last)
    {
        push_back(*first);
        first++;
    }
}

vector(const vector<T>& v)
    :_start(nullptr)
    , _finish(nullptr)
    , _end_of_storage(nullptr)
{
    vector<T> tmp(v.begin(), v.end());//复用上面的拷贝构造
    swap(tmp);
}

vector<T>& operator= (vector<T> v)
{
    swap(v);
    return *this;
}

~vector()
{
    delete[] _start;
    _start = _finish = _end_of_storage = nullptr;
}

注意: 

vector(size_t n, const T& val = T())
    :_start(nullptr)
    , _finish(nullptr)
    , _end_of_storage(nullptr)
{
    reserve(n);
    for (size_t i = 0; i < n; ++i)
    {
        push_back(val);
    }
}

template<class InputIterator>
vector(InputIterator first, InputIterator last)
    :_start(nullptr)
    , _finish(nullptr)
    , _end_of_storage(nullptr)
{
    while (first != last)
    {
        push_back(*first);
        first++;
    }
}

如上代码,如果我们把 vector(int n, const T& val = T()) 改为 vector(size_t n, const T& val = T()),会出现构造函数调用不明确的问题,如下

2.3 空间操作

小接口

size_t size() const
{
    return _finish - _start;
}

size_t capacity() const
{
    return _end_of_storage - _start;
}

 reserve()

void reserve(size_t n)
{
    if (n > capacity())
    {
        size_t sz = size();//提前保存,应对后面的finish更新问题
        T* tmp = new T[n];//new会调用构造函数,直接初始化
        if (_start)
        {
            //为了应对vector<vector<int>>的拷贝问题,建议reserve时不用传统的memcpy
            //memcpy(tmp, _start, sizeof(T) * sz);
            for (size_t i = 0; i < sz; i++)
            {
                tmp[i] = _start[i];
            }
            delete[] _start;//释放旧空间
        }
        _start = tmp;//原来的头指向新空间

        //_finish = _start + size();
        //finish - start +start=finish = 0,finish就变为nullptr了,所以要在开始就保存size()
        _finish = _start + sz;
        _end_of_storage = _start + n;

        //或者
        /*_finish = tmp + size();
        _start = tmp;
        _end_of_storage = _start + n;*/
    }
}

 resize()

void resize(size_t n, const T& val = T())
{
    if (n > capacity())
    {
        reserve(n);
    }
    if (n > size())
    {
        //初始化填值
        while (_finish < _start + n)
        {
            *_finish = val;
            ++_finish;
        }
    }
    else
    {
        //+删除数据
        _finish = _start + n;
    }
}

2.4 []重载

T& operator[](size_t pos)
{
    assert(pos < size());
    return _start[pos];
}

const T& operator[](size_t pos)const
{
    assert(pos < size());
    return _start[pos];
}

 2.5 数据操作接口

insert() 

insert和erase之后的pos位置,不要直接访问,要更新,不然会出现各种出乎意料的结果 ---- 迭代器失效

iterator insert(iterator pos, const T& x)
{                       //这里不能用引用,v.insert(v.begin(),1)时,begin返回_start的临时拷贝,这个拷贝有常性
    assert(pos >= _start);
    assert(pos <= _finish);
    迭代器失效
    如果本来有4个数,不扩容,
    然后要在pos前面插入一个数,要扩容
    然后数据被移到新空间去了,旧数据释放,但是这时候pos仍然指向旧空间的按个位置,变成野指针,发生迭代器失效
    // 所以不能简单的用下面的方式扩容,应该用下下面的方式来扩容
    //if (_finish == _end_of_storage)
    //{
    //	reserve(capacity() == 0 ? 4 : capacity() * 2);
    //}

    if (_finish == _end_of_storage)
    {
        size_t len = pos - _start;//保存长度
        reserve(capacity() == 0 ? 4 : capacity() * 2);
        pos = _start + len;//更新pos
    }

    // 挪动数据
    iterator end = _finish - 1;
    while (end >= pos)
    {
        *(end + 1) = *end;
        --end;
    }
    *pos = x;

    ++_finish;
    return pos;
}

 push_back()

void push_back(const T& x)
{
    if (_finish == _end_of_storage)
    {
        reserve(capacity() == 0 ? 4 : capacity() * 2);
    }

    *_finish = x;//finish位置为最后一个数的下一个位置
    ++_finish;
    //insert(end(), x);
}

pop_back()

void pop_back()
{
    assert(_finish > _start);
    --_finish;
}

 erase()

iterator erase(iterator pos)
{
    assert(pos >= _start);
    assert(pos < _finish);

    iterator begin = pos + 1;
    while (begin < _finish)
    {
        *(begin - 1) = *begin;
        ++begin;
    }

    --_finish;
    //if (size() < capacity()/2)
    //{
    //	// 缩容 -- 以时间换空间
    //}
    return pos;
}

三,完整代码

#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
#include<malloc.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
template<class T>
class vector
{
public:
    // Vector的迭代器是一个原生指针
    typedef T* iterator;
    typedef const T* const_iterator;
    iterator begin()
    {
        return _start;
    }
    iterator end()
    {
        return _finish;
    }

    const_iterator cbegin()
    {
        return _start;
    }

    const_iterator cend() const
    {
        return _finish;
    }
    // construct and destroy
    vector()
        : _start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {}

    vector(int n, const T& val = T())
        :_start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {
        reserve(n);
        for (size_t i = 0; i < n; ++i)
        {
            push_back(val);
        }
    }

    template<class InputIterator>
    vector(InputIterator first, InputIterator last)
        :_start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {
        while (first != last)
        {
            push_back(*first);
            first++;
        }
    }

    vector(const vector<T>& v)
        :_start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {
        vector<T> tmp(v.begin(), v.end());//复用拷贝构造
        swap(tmp);
    }

    vector<T>& operator= (vector<T> v)
    {
        swap(v);
        return *this;
    }

    ~vector()
    {
        delete[] _start;
        _start = _finish = _end_of_storage = nullptr;
    }

    // capacity
    size_t size() const
    {
        return _finish - _start;
    }

    size_t capacity() const
    {
        return _end_of_storage - _start;
    }

    void reserve(size_t n)
    {
        if (n > capacity())
        {
            size_t sz = size();//提前保存,应对后面的finish更新问题
            T* tmp = new T[n];//new会调用构造函数,直接初始化
            if (_start)
            {
                //为了应对vector<vector<int>>的拷贝问题,建议reserve时不用传统的memcpy
                //memcpy(tmp, _start, sizeof(T) * sz);
                for (size_t i = 0; i < sz; i++)
                {
                    tmp[i] = _start[i];
                }
                delete[] _start;//释放旧空间
            }
            _start = tmp;//原来的头指向新空间

            //_finish = _start + size();
            出bug,finish - start +start=finish = 0,finish就变为nullptr了,所以要在开始就保存size()
            _finish = _start + sz;
            _end_of_storage = _start + n;
            //或者
            /*_finish = tmp + size();
            _start = tmp;
            _end_of_storage = _start + n;*/
        }
    }

    void resize(size_t n, const T& val = T())
    {
        if (n > capacity())
        {
            reserve(n);
        }
        if (n > size())
        {
            //初始化填值
            while (_finish < _start + n)
            {
                *_finish = val;
                ++_finish;
            }
        }
        else
        {
            //+删除数据
            _finish = _start + n;
        }
    }

    ///access///
    T& operator[](size_t pos)
    {
        assert(pos < size());
        return _start[pos];
    }

    const T& operator[](size_t pos)const
    {
        assert(pos < size());
        return _start[pos];
    }

    ///modify/
    void push_back(const T& x)
    {
        if (_finish == _end_of_storage)
        {
            reserve(capacity() == 0 ? 4 : capacity() * 2);
        }

        *_finish = x;//finish位置为最后一个数的下一个位置
        ++_finish;
        //insert(end(), x);
    }

    void pop_back()
    {
        assert(_finish > _start);
        --_finish;
    }

    void swap(vector<T>& v)
    {
        std::swap(_start, v._start);
        std::swap(_finish, v._finish);
        std::swap(_end_of_storage, v._end_of_storage);
    }

    //insert和erase之后的pos位置,不要直接访问,要更新,不然会出现各种出乎意料的结果 ---- 迭代器失效
    iterator insert(iterator pos, const T& x)
    {                       //这里不能用引用,v.insert(v.begin(),1)时,begin返回_start的临时拷贝,这个拷贝有常性
        assert(pos >= _start);
        assert(pos <= _finish);
        迭代器失效
        如果本来有4个数,不扩容,
        然后要在pos前面插入一个数,要扩容
        然后数据被移到新空间去了,旧数据释放,但是这时候pos仍然指向旧空间的按个位置,变成野指针,发生迭代器失效
        // 所以不能简单的用下面的方式扩容,应该用下下面的方式来扩容
        //if (_finish == _end_of_storage)
        //{
        //	reserve(capacity() == 0 ? 4 : capacity() * 2);
        //}

        if (_finish == _end_of_storage)
        {
            size_t len = pos - _start;//保存长度
            reserve(capacity() == 0 ? 4 : capacity() * 2);
            pos = _start + len;//更新pos
        }

        // 挪动数据
        iterator end = _finish - 1;
        while (end >= pos)
        {
            *(end + 1) = *end;
            --end;
        }
        *pos = x;

        ++_finish;
        return pos;
    }

    iterator erase(iterator pos)
    {
        assert(pos >= _start);
        assert(pos < _finish);

        iterator begin = pos + 1;
        while (begin < _finish)
        {
            *(begin - 1) = *begin;
            ++begin;
        }

        --_finish;
        //if (size() < capacity()/2)
        //{
        //	// 缩容 -- 以时间换空间
        //}
        return pos;
    }

private:
    iterator _start; // 指向数据块的开始
    iterator _finish; // 指向有效数据的尾
    iterator _end_of_storage; // 指向存储容量的尾
};

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值