文章目录
- [从零实现一个简易 vector:C++ 模板与 STL 概念介绍](#从零实现一个简易 vector:C++ 模板与 STL 概念介绍)
-
- 一、为什么要用模板?
- 二、类与对象:封装你的数据结构
- 三、pushback:实现动态扩容
- 四、operator[]:支持下标访问与修改
- 五、push_pop:模拟弹出操作
- [六、STL 简介:为什么我们还需要标准库?](#六、STL 简介:为什么我们还需要标准库?)
- 七、知识点总结
- 最后一段代码回顾
从零实现一个简易 vector:C++ 模板与 STL 概念介绍
本文通过手写一个简易的
vector
类,带你理解 C++ 模板语法、内存管理、类与对象的基本原理,并对 STL 做一个入门级介绍。
一、为什么要用模板?
在 C 语言中,我们常常需要为不同类型写重复的代码,比如 int
数组、float
数组、char
数组......而 C++ 的模板机制让我们可以写一次代码,适用于任意类型。
cpp
template<class T>
class vector { ... };
这就是类模板的定义方式。编译器会根据你使用的类型自动生成对应的类,比如 vector<int>
、vector<double>
等。
二、类与对象:封装你的数据结构
vector
类封装了三个成员变量:
cpp
T* _a; // 动态数组指针
int _size; // 当前元素个数
int _capaity; // 当前容量
构造函数中使用 new
来动态分配内存:
cpp
_a = new T[num];
而析构函数中使用了 delete[]
来释放内存,避免内存泄漏:
cpp
delete[] _a;
这就是 C++ 中的内存管理收尾:new 和 delete 成对出现。
三、pushback:实现动态扩容
实现一个简易的 pushback()
方法:
cpp
if (_size >= _capaity) {
// 扩容逻辑
int newCapacity = _capaity == 0 ? 1 : _capaity * 2;
T* tmp = new T[newCapacity];
...
}
这是典型的 动态数组扩容策略:当容量不足时,翻倍扩容,保证摊销时间复杂度为 O(1)。
四、operator[]:支持下标访问与修改
重载 operator[]
,并返回引用:
cpp
T& operator[](size_t i) {
assert(i < _size);
return _a[i];
}
这允许我们像使用数组一样访问和修改元素:
cpp
v[1] = v[1] * 2;
如果你返回的是值而不是引用,就无法修改原始数据。下面我来解释一下原因,如果是传值返回,返回的并不是_a[i]
而是一份临时拷贝,但是因为临时拷贝具有常性,所以是没有办法进行修改的,因此我们必须加上引用!
五、push_pop:模拟弹出操作
实现一个 push_pop()
方法:
cpp
void push_pop() {
assert(_size > 0);
_size--;
}
虽然没有真正删除元素,但通过减少 _size
来模拟弹出行为,符合简易栈的思想。
六、STL 简介:为什么我们还需要标准库?
这份手写的 vector
是对 STL 中 std::vector
的简化版。STL(Standard Template Library)是 C++ 提供的一套泛型容器和算法库,包括:
容器 | 说明 |
---|---|
std::vector |
动态数组 |
std::list |
双向链表 |
std::map |
键值对红黑树 |
std::set |
唯一元素集合 |
std::queue |
队列 |
std::stack |
栈 |
STL 的优势在于:
- 模板泛型:支持任意类型
- 高性能:底层优化良好
- 安全性:边界检查、异常处理
- 线程安全性:部分算法是线程安全的,但容器本身不是,需手动加锁
七、知识点总结
知识点 | 说明 |
---|---|
模板语法 | template<class T> |
内存管理 | new / delete[] |
类封装 | 构造、析构、成员函数 |
运算符重载 | operator[] 返回引用 |
动态扩容 | 翻倍策略 |
STL 容器 | std::vector 等标准容器 |
最后一段代码回顾
cpp
vector<int> v(10);
v.pushback(1);
v.pushback(2);
v[1] = v[1] * 2;
for (size_t i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}