(C++ STL)vector类的简单模拟实现与源码展示

以下代码环境为 VS2022 C++。

一、前言

vector类 本质上就是数据结构中的顺序表。(可参考:顺序表的讲解与实现)

接下来我们来简单实现 vector类 和 部分对应函数。

参考:legacy.cplusplus.com中的 std::vector

二、vector 的成员变量

在 vector.hpp 中:

namespace my
{
	template<class T>
	class vector
	{
        // Vector的迭代器是一个原生指针
        typedef T* iterator;
        typedef const T* const_iterator;

        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

	private:

        iterator _start = nullptr;        // 指向数据块的开始
        iterator _finish = nullptr;       // 指向有效数据的尾
        iterator _endOfStorage = nullptr; // 指向存储容量的尾

	};
}

vector 的成员变量:

  1. vector 所存储数据的类型不确定,则使用模版。
  2. vector 的迭代器本质是指针变量,指向内存的地址。
  3. vector 有三个成员变量,_start、_finish、_endOfStorage,类型为 iterator。本质上都是指针变量,用来定位 vector 在内存上的位置。

vector 在内存中分布如图:

在这里插入图片描述

  1. 红色方块表示未开辟的空间,绿色方块表示有效数据,蓝色方块表示剩余存储容量。

  2. 这里采用 左闭右开 [ _start,_finish ),即 _start 开始就指向有效元素,_finish 指向最后一个元素的后面,_endOfStorage 同理。

三、vector 部分函数实现

size、capacity

vector 的有效长度和容量,是通过指针计算得到的。

指针 - 指针 得到的是中间的元素个数。

在 my::vector 中:

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

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

reserve

参考:std::vector::reserve

C++ 规定:

  1. 原空间 小于 需求空间 时,vector 扩容到需求空间或更多。

  2. 原空间 大于或等于 需求空间 时,vector 容量不变。

这里扩容严格按照 2 倍扩容。

在 vector.hpp 中:

template<class T>
void my::vector<T>::reserve(size_t n)
{
    if (n <= capacity())
    {
        return;
    }

    size_t newCapacity = capacity() == 0 ? MY_VECTOR_INIT_CAPACITY : capacity() * 2;

    while (newCapacity < n)
    {
        newCapacity <<= 1;
    }

    iterator newStart = new T[newCapacity];

    // 只能拷贝内置类型,如 string等非内置类型会失效
    //memcpy(newStart, _start, sizeof(T) * size());

    // 使用赋值拷贝
    for (int i = 0; i < size(); ++i)
    {
        newStart[i] = _start[i];
    }

    _finish = newStart + size();            // 指向代码不能交换位置
    _endOfStorage = newStart + newCapacity;

    delete[] _start;
    _start = newStart;
}

resize

参考:std::vector::resize

在 vector.hpp 中:

template<class T>
void my::vector<T>::resize(size_t n, const T& value)
{
    if (n > capacity())
    {
        reserve(n);

        iterator it = end();
        iterator over = begin() + n;

        while (it != over)
        {
            *it = value;
        }
    }

    _finish = begin() + n;
}

insert 与注意事项

参考:std::vector::insert

注意:
如果返回类型是在类里定义的,在类外使用时需要加上 typename 确定是类型,否则报错。

如 my::vector<T>::iterator 是类里 typedef 的一个类型,在类外使用时,编译器不能确定它是模版类的类型还是其静态变量,则会报错。

在 vector.hpp 中:

// 编译器不能分辨 my::vector<T>::iterator 是类型还是静态变量,
// 加上 typename 表示其为类型即可解决 
template<class T>   
typename my::vector<T>::iterator my::vector<T>::insert(my::vector<T>::iterator pos, const T& x)
{
    assert(_start <= pos && pos <= _finish);

    size_t sz = pos - begin();  // 考虑到扩容后 pos 可能失效,用中间值储存

    reserve(size() + 1);

    iterator it = nullptr;
    for (it = end(); it != begin() + sz; --it)
    {
        *it = *(it - 1);
    }
    *it = x;

    resize(size() + 1);

    return it + 1;
}

erase

参考:std::vector::erase

在 vector.hpp 中:

template<class T>
typename my::vector<T>::iterator my::vector<T>::erase(my::vector<T>::iterator pos)
{
    assert(size() != 0);
    assert(_start <= pos && pos < _finish);

    for (iterator it = pos; it != end() - 1; ++it)
    {
        *it = *(it + 1);
    }
    --_finish;

    return pos;
}

构造、析构、赋值拷贝

参考:std::vector::vector
参考:std::vector::~vector
参考:std::vector::operator=

在 my::vector 中:

        vector() = default; // default 后编译器会自动生成默认构造

        vector(size_t n, const T& value = T())
        {
            reserve(n);
            resize(n);

            for (auto& val : *this)
            {
                val = value;
            }
        }

        vector(int n, const T& value = T())
        {
            reserve(n);
            resize(n);

            for (auto& val : *this)
            {
                val = value;
            }
        }

        template<class InputIterator>
        vector(InputIterator first, InputIterator last)
        {
            while (first != last)
            {
                push_back(*first);

                ++first;
            }
        }

        vector(const vector<T>& v)
        {
            reserve(v.capacity());
            for (auto& val : v)
            {
                push_back(val);
            }
        }

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

        vector<T>& operator= (vector<T> v)
        {
            swap(v);

            return *this;
        }

        ~vector()
        {
            if (_start != nullptr)
            {
                delete[] _start;
                _start = nullptr;
            }

            _finish = _endOfStorage = _start;
        }

四、vector 源代码

在 vector.hpp 中:

#pragma once

#include <iostream>
#include <cassert>

#define MY_VECTOR_INIT_CAPACITY 4

namespace my
{
    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 begin() const
        {
            return _start;
        }

        const_iterator end() const
        {
            return _finish;
        }

        //--------------------------------------

        vector() = default; // default 后编译器会自动生成默认构造

        vector(size_t n, const T& value = T())
        {
            reserve(n);
            resize(n);

            for (auto& val : *this)
            {
                val = value;
            }
        }

        vector(int n, const T& value = T())
        {
            reserve(n);
            resize(n);

            for (auto& val : *this)
            {
                val = value;
            }
        }

        template<class InputIterator>
        vector(InputIterator first, InputIterator last)
        {
            while (first != last)
            {
                push_back(*first);

                ++first;
            }
        }

        vector(const vector<T>& v)
        {
            reserve(v.capacity());
            for (auto& val : v)
            {
                push_back(val);
            }
        }

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

        vector<T>& operator= (vector<T> v)
        {
            swap(v);

            return *this;
        }

        ~vector()
        {
            if (_start != nullptr)
            {
                delete[] _start;
                _start = nullptr;
            }

            _finish = _endOfStorage = _start;
        }

        //--------------------------------------

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

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

        void reserve(size_t n);

        void resize(size_t n, const T& value = T());

        //--------------------------------------

        T& operator[](size_t pos)
        {
            return *(begin() + pos);
        }

        const T& operator[](size_t pos) const
        {
            return *(begin() + pos);
        }

        //--------------------------------------

        void push_back(const T& x)
        {
            insert(end(), x);
        }

        void pop_back()
        {
            erase(end() - 1);
        }

        iterator insert(iterator pos, const T& x);

        iterator erase(iterator pos);

    private:

        iterator _start = nullptr;        // 指向数据块的开始
        iterator _finish = nullptr;       // 指向有效数据的尾
        iterator _endOfStorage = nullptr; // 指向存储容量的尾
    };

}

template<class T>
void my::vector<T>::reserve(size_t n)
{
    if (n <= capacity())
    {
        return;
    }

    size_t newCapacity = capacity() == 0 ? MY_VECTOR_INIT_CAPACITY : capacity() * 2;

    while (newCapacity < n)
    {
        newCapacity <<= 1;
    }

    iterator newStart = new T[newCapacity];

    // 只能拷贝内置类型,如 string等非内置类型会失效
    //memcpy(newStart, _start, sizeof(T) * size());

    // 使用赋值拷贝
    for (int i = 0; i < size(); ++i)
    {
        newStart[i] = _start[i];
    }

    _finish = newStart + size();            // 指向代码不能交换位置
    _endOfStorage = newStart + newCapacity;

    delete[] _start;
    _start = newStart;
}

template<class T>
void my::vector<T>::resize(size_t n, const T& value)
{
    if (n > capacity())
    {
        reserve(n);

        iterator it = end();
        iterator over = begin() + n;

        while (it != over)
        {
            *it = value;
        }
    }

    _finish = begin() + n;
}

// 编译器不能分辨 my::vector<T>::iterator 是类型还是静态变量,
// 加上 typename 表示其为类型即可解决 
template<class T>   
typename my::vector<T>::iterator my::vector<T>::insert(my::vector<T>::iterator pos, const T& x)
{
    assert(_start <= pos && pos <= _finish);

    size_t sz = pos - begin();  // 考虑到扩容后 pos 可能失效,用中间值储存

    reserve(size() + 1);

    iterator it = nullptr;
    for (it = end(); it != begin() + sz; --it)
    {
        *it = *(it - 1);
    }
    *it = x;

    resize(size() + 1);

    return it + 1;
}

template<class T>
typename my::vector<T>::iterator my::vector<T>::erase(my::vector<T>::iterator pos)
{
    assert(size() != 0);
    assert(_start <= pos && pos < _finish);

    for (iterator it = pos; it != end() - 1; ++it)
    {
        *it = *(it + 1);
    }
    --_finish;

    return pos;
}

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值