从零实现 STL vector 源码解析
前言
在深入理解 C++ 类和对象、动态内存管理及模板机制之前,我们不妨通过手写一个 vector 来实战演练。作为 STL 中最常用的序列容器,vector 的底层实现涵盖了 C++ 核心特性的诸多细节。
vector 前置知识
1. 什么是 vector?
vector 是 STL 库中提供的类模板,本质上是一个顺序表。它支持通过下标随机访问元素,并提供了丰富的增删查改接口。其核心优势在于内存连续存储,这使得缓存友好性极高。
2. 常用接口概览
本文后续将详细拆解 vector 的核心接口实现。这些接口足以覆盖日常开发中的大部分需求。若需了解更详尽的标准库文档,可参考 C++ Reference 官方资料。
源码实现详解
1. 成员变量与整体框架
不同于传统的顺序表仅记录指针和大小,STL vector 采用了三个关键迭代器(实际为指针)来管理内存:
_start:指向有效数据起始位置。_finish:指向有效数据结束位置的下一个位置。_endofstorage:指向已分配空间结束位置的下一个位置。
这种设计使得我们可以轻松计算当前元素个数(_finish - _start)和剩余容量(_endofstorage - _start)。初始化时直接赋予空指针默认值,能避免多次显式初始化的冗余。
2. 构造函数
(1) 空构造
虽然声明时已有默认值,但必须显式定义空构造函数,否则编译器不会自动生成默认版本,这会影响派生类或其他构造函数的调用。
(2) n 个元素初始化
参数中使用了 T() 作为缺省值。对于内置类型如 int,C++ 会将其视为可调用默认构造的对象,返回 0;对于自定义类型,则调用其默认构造函数。这种泛型处理保证了接口的通用性。
(3) 迭代器区间初始化
支持任意输入迭代器范围进行初始化,体现了模板的强大之处。内部逻辑是通过遍历源范围,逐个拷贝元素到新分配的内存中。
3. 基础性质查询
- size():返回
_finish - _start,即当前元素个数。 - capacity():返回
_endofstorage - _start,即当前已分配的空间大小。
4. 拷贝控制
拷贝构造函数
这里严禁使用 memcpy。如果元素类型 T 包含动态资源(如指针),按字节拷贝会导致浅拷贝问题,引发双重释放。必须逐元素调用赋值运算符或构造函数进行深拷贝,确保每个对象独立管理资源。
赋值运算符重载
采用经典的'复制 - 交换'(Copy-and-Swap)惯用法。形参传值触发拷贝构造,随后调用 swap 交换内部指针,最后临时对象析构释放旧内存。这种方式天然具备异常安全性。
交换函数
利用算法库中的 std::swap 交换三个指针成员,时间复杂度 O(1),效率极高。
5. 迭代器与操作符
begin/end
提供 const 和非 const 重载版本,分别返回只读和读写迭代器。begin 指向首元素, 指向尾后位置。


