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,异常安全、极简。
相关推荐
机器学习之心2 小时前
信号分解和小波阈值联合降噪 | NRBO-FMD基于牛顿拉夫逊算法优化特征模态分解+皮尔逊系数+小波阈值降噪+信号重构,MATLAB代码
算法·matlab·重构·nrbo-fmd·特征模态分解
Lauren_Blueblue2 小时前
第十六届蓝桥杯省赛Python研究生组-F串
python·算法·蓝桥杯·算法基础
鲸渔2 小时前
【C++ 入门】第一个程序:Hello World 与基本语法规则
开发语言·c++·算法
EverestVIP2 小时前
C++ 仿函数(Functors)
c++
‎ദ്ദിᵔ.˛.ᵔ₎2 小时前
滑动窗口算法
算法·哈希算法
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章46-矩形卡尺
图像处理·人工智能·opencv·算法·计算机视觉
仟濹2 小时前
【算法打卡day39(2026-04-06~08 周一~周三)】(10道蓝桥杯真题)今日练习:蓝桥杯第13届省赛B组Cpp组
算法·职场和发展·蓝桥杯
美式请加冰2 小时前
最短路径问题
java·数据结构·算法
会编程的土豆2 小时前
【数据结构与算法】 时间复杂度计算
数据结构·c++·算法