C++ STL vector 原理到模拟实现

1. vector 核心认识

  • vector 是可变长数组,底层连续存储,支持随机访问。
  • 维护三个指针:
    • _start:数据起始
    • _finish:有效数据末尾
    • _end_of_storage:容量末尾
  • 扩容机制:VS (PJ) 约 1.5 倍 ,G++(SGI) 2 倍
  • 关键特性:支持随机访问、尾部增删 O (1)、中间增删 O (N)、迭代器可能失效

2. 必须掌握的核心接口

2.1 构造函数

cpp 复制代码
// 1. 无参构造
vector();
// 2. 构造 n 个 val
vector(size_t n, const T& val = T());
// 3. 拷贝构造(深拷贝)
vector(const vector& v);
// 4. 迭代器区间构造
template<class InputIterator>
vector(InputIterator first, InputIterator last);

2.2 容量与大小

cpp 复制代码
size_t size() const;         // 有效数据个数
size_t capacity() const;     // 容量
bool empty() const;          // 是否为空
void reserve(size_t n);      // 只改容量,不初始化
void resize(size_t n, const T& val = T()); // 改size+初始化

2.3 增删改查

cpp 复制代码
void push_back(const T& x);     // 尾插
void pop_back();                // 尾删
iterator insert(iterator pos, const T& x); // 插入
iterator erase(iterator pos);           // 删除
T& operator[](size_t i);                // 随机访问
void swap(vector<T>& v);                // 交换(O(1))

3. 迭代器失效

3.1 导致失效的操作

所有引起扩容 的操作:reserve/resize/insert/push_back底层空间被释放,原迭代器变成野指针。

3.2 erase 导致失效

删除后元素前移,被删位置迭代器失效。正确写法

cpp 复制代码
it = v.erase(it); 

而非直接 erase(it)++it

3.3 解决方法

使用前重新获取迭代器


4. 深拷贝与 memcpy 陷阱

  • vector 扩容必须深拷贝,逐个元素赋值。
  • 禁止用 memcpy :memcpy 是浅拷贝,若元素是 string/vector 等带资源类型,会导致重复释放、崩溃

5. vector 模拟实现(可直接运行)

5.1 成员变量

cpp 复制代码
template<class T>
class vector
{
public:
    typedef T* iterator;
    typedef const T* const_iterator;

private:
    iterator _start = nullptr;
    iterator _finish = nullptr;
    iterator _end_of_storage = nullptr;
};

5.2 构造 / 析构 / 拷贝 / 赋值

cpp 复制代码
// 无参构造
vector() = default;

// n 个 val
vector(size_t n, const T& val = T())
{
    reserve(n);
    for (size_t i = 0; i < n; ++i)
        _start[i] = val;
    _finish = _start + n;
}

// 迭代器区间构造
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
    while (first != last)
        push_back(*first++);
}

// 拷贝构造(深拷贝)
vector(const vector<T>& v)
{
    reserve(v.capacity());
    for (size_t i = 0; i < v.size(); ++i)
        _start[i] = v._start[i];
    _finish = _start + v.size();
    _end_of_storage = _start + v.capacity();
}

// 赋值重载(现代写法)
vector<T>& operator=(vector<T> v)
{
    swap(v);
    return *this;
}

// 析构
~vector()
{
    delete[] _start;
    _start = _finish = _end_of_storage = nullptr;
}

5.3 迭代器

cpp 复制代码
iterator begin() { return _start; }
iterator end() { return _finish; }
const_iterator begin() const { return _start; }
const_iterator end() const { return _finish; }

5.4 容量 / 大小 / 访问

cpp 复制代码
size_t size() const { return _finish - _start; }
size_t capacity() const { return _end_of_storage - _start; }
bool empty() const { return size() == 0; }

T& operator[](size_t i) { return _start[i]; }
const T& operator[](size_t i) const { return _start[i]; }

5.5 reserve / resize

cpp 复制代码
void reserve(size_t n)
{
    if (n > capacity())
    {
        size_t oldSize = size();
        T* tmp = new T[n];
        for (size_t i = 0; i < oldSize; ++i)
            tmp[i] = _start[i];
        delete[] _start;
        _start = tmp;
        _finish = _start + oldSize;
        _end_of_storage = _start + n;
    }
}

void resize(size_t n, const T& val = T())
{
    size_t oldSize = size();
    if (n > oldSize)
    {
        reserve(n);
        for (size_t i = oldSize; i < n; ++i)
            _start[i] = val;
    }
    _finish = _start + n;
}

5.6 增删

cpp 复制代码
void push_back(const T& x)
{
    if (_finish == _end_of_storage)
        reserve(capacity() == 0 ? 4 : capacity() * 2);
    *_finish++ = x;
}

void pop_back()
{
    assert(!empty());
    --_finish;
}

iterator insert(iterator pos, const T& x)
{
    size_t len = pos - _start;
    if (_finish == _end_of_storage)
        reserve(capacity() == 0 ? 4 : capacity() * 2);
    pos = _start + len;
    for (iterator it = _finish; it > pos; --it)
        *it = *(it - 1);
    *pos = x;
    ++_finish;
    return pos;
}

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

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

6. 总结

  1. vector 是连续存储的动态数组。
  2. 扩容是开新空间→拷贝→释放旧空间,不是原地扩展。
  3. 迭代器失效是手写 vector 最常见 bug。
  4. 元素带资源时不能用 memcpy,必须深拷贝。
  5. reserve 只扩容量,resize 改 size 并初始化。
  6. 现代写法赋值运算符:传参拷贝 + swap,异常安全、极简。
相关推荐
x_yeyue1 小时前
三角形数
笔记·算法·数论·组合数学
念何架构之路2 小时前
Go语言加密算法
数据结构·算法·哈希算法
AI科技星2 小时前
《数学公理体系·第三部·数术几何》(2026 年版)
c语言·开发语言·线性代数·算法·矩阵·量子计算·agi
小小编程路2 小时前
C++ 多线程与并发
java·jvm·c++
失去的青春---夕阳下的奔跑2 小时前
560. 和为 K 的子数组
数据结构·算法·leetcode
黎阳之光2 小时前
黎阳之光:以视频孪生重构智慧医院信息化,打造高标项目核心竞争力
大数据·人工智能·物联网·算法·数字孪生
丷丩3 小时前
三级缓存下MVT地图瓦片服务性能优化策略
算法·缓存·性能优化·gis·geoai-up
m0_629494733 小时前
LeetCode 热题 100-----25.回文链表
数据结构·算法·leetcode·链表
程序leo源3 小时前
Qt窗口详解
开发语言·数据库·c++·qt·青少年编程·c#
zh_xuan4 小时前
解决VS Code 控制台中文乱码
c++·vscode·乱码