从零开始手写STL库:Vector

从零开始手写STL库–Vector部分

Github链接:miniSTL



Vector是什么

std::vector 是一个动态数组,它在内存中以连续的块存储元素。与静态数组相比,std::vector 允许在运行时动态调整大小,而无需手动管理内存。

Vector需要包含什么函数

应当具有:

1)基础成员函数

构造函数:初始化Vector
析构函数:释放内存,当运行结束后要摧毁这个Vector防止内存泄漏
拷贝构造函数:允许用已有的Vector创建新的Vector
拷贝赋值操作符:允许多个Vector相互赋值

2)核心功能

push_back:在vector末尾加入元素
size:获取vector的长度
get:访问vector某处的元素
pop_back:移除vector末尾的元素
insert:在vector某处插入元素
clear:清空vector

基础成员函数的编写

Vector的成员:
一个Vector应当有指向它的指针、Vector的容量和Vector目前的长度,这样才能方便调用,以及判断是否需要扩充

template <typename T>
class myVector
{
private:
    T * elements;
    size_t capacity;
    size_t current_size;
};

那么构造函数和析构函数也就出来了,为以上三个元素赋初值,运行结束时释放elements即可

public:
    myVector() : elements(nullptr), capacity(0), current_size(0){}
    ~myVector()
    {
        delete[] elements;
    }

那么拷贝构造函数是不是就是:

myVector(const myVector & other) : 
	elements(other.elements), capacity(other.capacity), current_size(other.current_size)

那就错了,这里elements并不是真实的数组,而是数组的指针,如果这么做的话,对other的操作会影响这里
所以这里elements需要额外创造一个数组来复制它,数据一样,指针不同

myVector(const myVector & other) : capacity(other.capacity), current_size(other.current_size)
{
    elements = new T[capacity];                                                 // copy arrays of the same length 
    std::copy(other.elements, other.elements + current_size, elements);         // fill the array and finish copying
}

拷贝赋值操作符和拷贝构造函数很像,但是要先释放当前的elements指针,防止内存泄漏

    myVector &operator = (const myVector & other)
    {
        if(this != other)
        {
            delete[] elements;
            capacity = other.capacity;
            current_size = other.current_size;
            elements = new T[other.capacity];
            std::copy(other.elements, other.elements + current_size, elements);
        }
        return *this;
    }

这里不能直接调用析构函数和拷贝构造函数,因为析构函数和拷贝构造函数的调用不会像普通函数那样直接调用,而是通过对象的生命周期管理机制自动调用

核心功能函数的编写

1、push back函数:将元素加入到vector的末尾
试想这样一个流程:初始化vector->push_back,此时vector的数组大小还是0,根本没法push进去
所以先写一个分配内存的函数

    void reserve(size_t newCapacity)
    {
        if (newCapacity > capacity)
        {
            T *newElements = new T[newCapacity];
            std::copy(elements, elements + current_size, newElements);
            delete[] elements;
            elements = newElements;
            capacity = newCapacity;
        }
    }

这样就可以在push前检查一下是否有余量,无余量了就扩充数组内容

    void push_back(const T & input)
    {
        if(current_size == capacity)
        {
            capacity ? reserve(2 * capacity) : reserve(1);
        }
        elements[current_size++] = input;
    }

2、size函数:获取当前vector长度

    size_t size()
    {
        return current_size;
    }

3、get函数:访问vector某处的元素
这里模仿c++库中的vector,希望实现的是通过vector[index]来获取index处的元素

    T & operator[](size_t index)
    {
        if(index >= current_size) std::cout << "Index overstep" << std::endl;
        return elements[index];
    }
    const T & operator[](size_t index) const
    {
        if(index >= current_size) std::cout << "Index overstep" << std::endl;
        return elements[index];
    }

这里区分const和non-const是为了防止以下问题的出现:当vector本身有const时,操作符也要有const属性
在这里插入图片描述
4、pop back函数:移除vector末尾的元素

    void pop_back()
    {   
        if(current_size) current_size--;
    }

5、insert函数:在vector某处插入元素
这里要考虑两种情况:
一是index超出了数组范围,那么要说越界
二是index没超出范围,但是数组已经满了怎么办
三就是正常的后移index后面的元素,再插入index

    void insert(const size_t index, const T & input)
    {
        if(index > current_size) throw std::out_of_range("Index overstep");
        if(current_size == capacity) reserve(capacity == 0 ? 1 : 2 * capacity);
        for(size_t i = current_size; i > index; i --)
        {
            elements[i] = elements[i - 1];
        } 
        elements[index] = input;
        current_size ++;
    }

6、clear函数:清空vector

    void clear()
    {
        current_size = 0;
    }

7、其他函数
在使用for(auto ele : myVector)时发现出现错误:此基于范围的for语句需要合适的begin函数,但未找到
所以还需要在class中定义这些信息

    T* begin()
    {
        return elements;
    }

    T* end()
    {
        return elements + current_size;
    }

    const T* begin() const
    {
        return elements;
    }

    const T* end() const
    {
        return elements + current_size;
    }

完整的代码在:Github 中,编译建议在Linux系统中,因为本人是在Ubuntu18中编写的

理论上Windows也可以运行

总结

Vector简单实现并不算难,代码也不复杂,但是真要和C++的STL正经实现相比,还是差非常多的,写下来是为了理解vector在处理数组长度不足时怎么申请内存以及释放内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值