Vector C++ implementation

本文最后更新于:2022年11月22日 下午

成员变量cap_记录了容量大小,而size_则记录了实际存储的元素的数量,iniVal作为const值表示MyVector对象创建时为其预分配的容量大小,vector则是指针,其指向的应该是对象数组的起始地址

1
2
3
4
5
private:
T *vector = nullptr;
size_t cap_;
size_t size_;
const int iniVal = 20;

首先看一下构造函数,其中会使用malloc分配指定大小的内存区域,并把起始地址赋给vector

1
2
3
4
5
MyVector(){
cap_ = iniVal;
size_ = 0;
vector = (T*) malloc(sizeof (T) * cap_);
}

实现的重点在于push_back函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
void push_back(const T &data){
if(size_ < cap_){
*(vector + size_) = data;
size_++;
}else{
vector = (T*)realloc(vector, sizeof(T) * cap_ * 2);
cap_ *= 2;
if(vector){
*(vector + size_) = data;
size_ ++;
}
}
}

如果容量足够(size_ < cap_),直接赋值即可;如果容量不够,我们将容量翻倍,并调用realloc[1]重新分配内存,realloc对于扩大内存操作会将传入的指针指向的内存中的数据复制到新地址,并释放原指针指向的内存空间。

在这里需要注意的是realloc是可能会分配失败的 ,它会返回NULL,所以在赋值前会加入相应的检查判断,然而在这里我欠缺了分配失败后的处理逻辑。

pop_back则很简单,只需要将size_递减即可,不需要对那部分数据有任何操作,因为不管那个位置上的值是否有效,由cap_指定大小的一块内存区域已经分配给了MyVector使用,如果有后续的元素加入,它会直接进行覆盖。

不过这样实现显然会有一些缺陷,因为它并非那么“动态”:一旦cap_扩大后,却没有任何缩减cap_的逻辑,实际上可能会造成内存使用上的浪费,这是需要改进的一个点。

全部代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using namespace std;
template<typename T>
class MyVector{
private:
T *vector = nullptr;
size_t cap_;
size_t size_;
const int iniVal = 20;
public:
MyVector(){
cap_ = iniVal;
size_ = 0;
vector = (T*) malloc(sizeof (T) * cap_);
}
~MyVector(){
free(vector);
}
T& operator[](size_t pos){
return *(this->vector + pos);
}
size_t size(){
return size_;
}
void push_back(const T &data){
if(size_ < cap_){
*(vector + size_) = data;
size_++;
}else{
vector = (T*)realloc(vector, sizeof(T) * cap_ * 2);
cap_ *= 2;
if(vector){
*(vector + size_) = data;
size_ ++;
}
}
}
void pop_back(){
size_--;
}
};

参考


Vector C++ implementation
https://flaglord.com/2021/09/29/Vector-C-implementation/
作者
flaglord
发布于
2021年9月29日
许可协议