C++--vector第二讲:手写 C++ STL:vector 源码剖析与迭代器失效分析


博主名称:deM0one ⭐️C++专栏: C++ ⭐️C++vector第一讲: vector第一讲

文章目录

  • [手写 C++ STL:vector 源码剖析与迭代器失效实战](#手写 C++ STL:vector 源码剖析与迭代器失效实战)

手写 C++ STL:vector 源码剖析与迭代器失效实战

一、写在前面

  • 为什么手写 vector:深入理解 STL 底层机制,从"会用"到"懂原理"
  • 本系列基于课堂手写实现,并与 VS2019 / Linux 实际运行结果对照

二、vector 的内存布局

  • 三大指针:_start_finish_end_of_storage
    • begin()_start(首元素)
    • end()_finish(最后一个元素的下一个位置)
    • capacity()_end_of_storage(容量边界)
  • size()capacity() 的区别
  • reserve(capacity()) 的用途:确保不扩容时空间充足

三、size 与 capacity 的关系

  • 三种情形:
    • n < size:不允许缩小容量
    • size < n < capacity:容量已够,无需扩容
    • n > capacity:触发真正的扩容

四、构造函数家族

  • vector(size_t n):构造 n 个默认元素
  • vector(size_t n, const T& val):构造 n 个 val
  • 区间构造函数(重点)
    • template <class InputIterator> vector(InputIterator first, InputIterator last)
    • 可用任意容器的迭代器区间初始化(如 list 的迭代器构造 vector
    • 要求迭代器类型与元素类型匹配
  • 知识点:类模板的成员函数还可以是函数模板
    • <T> 只是给 IntelliSense 看的示例模板参数

五、reserve 的实现与深拷贝陷阱

  • 实现步骤:
    1. n > capacity() 时才扩容
    2. 记录旧大小 old_size
    3. new T[n] 申请新空间
    4. 拷贝旧数据到新空间
    5. delete[] _start 释放旧空间
    6. 更新 _start_finish_end_of_storage
  • 坑点 1:用 memcpy 是浅拷贝
    • vector<string>vector<vector<int>> 等非 POD 类型,memcpy 会复制指针而非内容
    • 调试器中出现"读取字符串字符时出错",旧内存释放后成为野指针/悬垂指针
  • 正确做法:用 for 循环逐元素赋值 tmp[i] = start[i](深拷贝语义)

六、insert 与迭代器失效(核心重点)

  • iterator insert(iterator pos, const T& x) 的流程
    • end() 开始倒着向后搬移元素,为插入位置腾出空间
    • 插入新元素后更新 _finish
  • 迭代器失效问题
    • insert 后数据发生挪动,原迭代器 p 指向的元素已改变("位置意义已经变了")
    • 结论:insert 之后原迭代器视为失效,不要访问
    • 若一定要用,必须先更新迭代器
  • 失效后的真实表现
    • VS2019 强制检查:访问失效迭代器直接报错
    • 程序退出码 -1073741819(即 0xC0000005,访问冲突)

七、erase 与返回值

  • iterator erase(iterator position) 的实现
    • 断言保护:POS < _finish(如 vector.h 第 110 行 Assertion failed)
    • 删除后向前搬移后续元素
  • 返回值语义(官方说明)
    • 返回被删除元素的后一个元素的迭代器
    • 若删除的是最后一个元素,返回 end()

八、野指针与程序崩溃案例分析

  • 案例:insert 后继续使用旧迭代器 → 野指针 → 崩溃
  • 对比 VS2019 与 Linux 下 ./a.out 的不同表现(强制检查 vs 静默出错)
  • 调试技巧:通过退出码与断言信息定位问题

九、综合实战

  • 编写 print_container 模板打印任意容器
    • const vector<T>& 传参 + auto& e 遍历
  • 多种初始化方式对比
    • 直接构造、区间构造、v1.begin() + 3 子区间构造
    • vector<int> v2(v1.begin(), v1.end())
    • vector<int> v3(lt.begin(), lt.end())(list 迭代器初始化)

十、总结

  • vector 三指针结构一句话回顾
  • 扩容 = 申请 + 拷贝 + 释放 + 更新指针
  • 迭代器失效的黄金法则:增删元素后不要继续使用旧迭代器
  • 延伸思考:list / deque 的迭代器失效规则有什么不同?

任何的批评与建议欢迎指出,我们共同进步!

相关推荐
程序员-珍1 小时前
安卓开发:同名 styles.xml 在不同分支/文件夹的合并规则
android·xml·前端
资源大佬星 课it1 小时前
黑马 Java+AI新版V16零基础就业班视频课程百度网盘下载
java·开发语言·人工智能
郝学胜-神的一滴1 小时前
[简化版 GAMES 104] 现代游戏引擎 06:从Tick时序到邮局模型,拆解确定性世界的底层密码
开发语言·c++·游戏引擎·图形渲染·软件开发·opengl
二十雨辰1 小时前
[Java]-微服务面试题
java·开发语言·微服务
不会代码的小猴1 小时前
6. Qt网络编程
开发语言·c++·笔记·qt·算法
我命由我123451 小时前
Compose Codelab 学习 - Compose 中的基本布局
android·java·java-ee·kotlin·android studio·android-studio·android runtime
ii_best1 小时前
手机自动化脚本按键精灵实战:随机布局安全数字键盘的自动化输入方案
android·运维·ios·自动化·手机
沐风老师1 小时前
从零开始学3dMax插件开发!
c++·3dmax插件·3dmax·maxscript
2601_965798471 小时前
Boutique Business Consulting WordPress Architecture & SEO Setup
android·theme·wordpress