当前位置: 首页 > news >正文

STL容器终极解剖:C++ vector源码级实现指南 | 从内存分配到异常安全的全流程避坑

🤖💻👨‍💻👩‍💻🌟🚀
🤖🌟 欢迎降临张有志的未来科技实验室 🤖🌟
专栏: C++
👨‍💻👩‍💻 先赞后看,已成习惯👨‍💻👩‍💻
👨‍💻👩‍💻 创作不易,多多支持👨‍💻👩‍💻
🚀 启动创新引擎,揭秘C语言的密码🚀
图片

文章目录

  • C++ Vector模拟实现全景
  • 核心接口
  • 🧠 核心实现原理
  • 关键组件实现:
    • 👨💻 vector接口实战演练
  • 性能优化关键

C++ Vector模拟实现全景

用户代码 push_back vector operator new memcpy operator delete 添加元素 检查容量 直接插入 申请新内存 返回指针 数据迁移 迁移完成 释放旧内存 alt [容量足够] [需要扩容] 用户代码 push_back vector operator new memcpy operator delete

核心接口

内存管理
_start指针
_finish指针
_end_of_storage指针
核心接口
push_back
insert
erase
迭代器体系
正向迭代器
const迭代器
🔧 STL vector是C++中最核心的顺序容器,其实现涉及以下关键技术点:
  1. 三段式指针管理:

    • _start → 存储空间起始
    • _finish→ 有效数据末尾
    • _end_of_storage → 内存空间末尾
  2. 扩容策略:

    首次push_back
    倍增策略
    空容器
    预分配4元素空间
    容量不足
    新容量=旧容量*2
  3. 深拷贝处理:

    // 拷贝构造函数示例
    vector(const vector<T>& v) {reserve(v.size());for (auto& e : v) push_back(e);
    }
    

🧠 核心实现原理

容量增长公式:
n e w _ c a p a c i t y = m a x ( o l d _ c a p a c i t y × 2 , d e m a n d ) new\_capacity = max(old\_capacity × 2, \ demand) new_capacity=max(old_capacity×2, demand)

push_back() reserve() operator new() std::copy() _finish 准备插入新元素 发起容量检查请求 检查当前容器容量 请求分配新内存 返回新内存指针 发起数据迁移请求 数据迁移完成通知 无需扩容,直接插入 alt [容量不足] [容量充足] 插入新元素 新元素插入完成 push_back() reserve() operator new() std::copy() _finish

💡贴士: 迭代器本质是原生指针的封装,需实现operator++operator*

关键组件实现:

// 三段式指针定义
template <class T>
class vector {
public:
using iterator = T*;
using const_iterator = const T*T* _start;          // 内存起始T* _finish;         // 有效数据末尾T* _end_of_storage; // 内存空间末尾
};

构造函数: 用于创建 vector 对象,包括默认构造、拷贝构造以及根据指定元素个数和范围构造等。

	//部分构造vector(iterator start=nullptr, iterator finish = nullptr, iterator end_of_storage = nullptr):_start(start)\,_finish(finish)\,_end_of_storage(end_of_storage){}//拷贝构造vector(const vector<T>& v) {reserve(v.size());for (auto& e : v)push_back(e);}//构造template<class T> vector(size_t n, const T& val=T()):_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){reserve(n);while (n--) {push_back(val);}}	//部分template<class T> vector(T first, T last) {while (first != last) {push_back(*first);++first;}}

析构函数:负责释放 vector 对象占用的资源。

	~vector() {if (_start) {clear();}_start = _finish = _end_of_storage = nullptr;}

需要注意:不能直接使用delete[],会导致程序崩溃(vector<vector< T >>),需要挨个调用~T()

容量管理接口:

  • reserve:预留指定容量的存储空间。
void reserve(size_t n) {//防止给定数字比容量小if(n>capacity()){size_t old_size = size();T* tmp = new T[n];std::copy(_start, _finish, tmp);delete[] _start;_start = tmp;_finish = tmp + old_size;_end_of_storage = _start + n;} else {return;}
}
  • capacity:返回当前 vector 的容量。
		//容器总容量
size_t capacity() {return _end_of_storage - _start;
}
  • size:返回当前 vector 中元素的数量。
size_t size()const {return _finish - _start;
}
  • rest_size:返回当前 vector 剩余的可存储元素的空间大小。
size_t rest_size() {return capacity() - size();
}

迭代器接口:

  • begin 和 end:返回指向 vector 首元素和尾后元素的迭代器。
		//首元素iterator begin() {return _start;}//有效尾元素iterator end() {return _finish;}const_iterator begin() const {return _start;}const_iterator end() const {return _finish;}

元素操作接口:

  • push_back:在 vector 尾部插入一个元素。
void push_back(const T& v) {if (_finish == _end_of_storage) {reserve(capacity() == 0 ? 4 : 2 * size());}*_finish = v;++_finish;
}
  • insert:在指定位置插入一个元素。
T& insert(size_t pos, const T& v) {if (_finish == _end_of_storage)reserve(capacity() == 0 ? 4 : 2 * size());for (size_t i = size(); i > pos; --i)*(_start + i) = *(_start + i - 1);_start[pos] = v;++_finish;return *_finish;
}
  • erase:删除指定位置的元素。
iterator erase(size_t pos) {if (pos<begin() || pos>end()) {throw std::out_of_range("无效位置");}size_t offset = pos - begin();auto m_pos = _start + offset;m_pos->~T();if (m_pos + 1 != _finish) {std::move(m_pos + 1, _finish, m_pos);}return m_pos;
}
  • clear:清空 vector 中的所有元素。
void clear() {for (auto it = _start; it != _end_of_storage; ++it) {it->~T();}_start = _finish;
}

查找和调整大小接口:

  • find:查找指定元素在 vector 中的位置。
template<class T> int find(const my::vector<T>& dst) {iterator bg = begin();iterator ed = end();int pos = 0;while (bg < ed) {if (*bg == dst)return pos;else {++pos;++bg;}}return -1;
}
  • resize:调整 vector 的大小。
void resize(size_t n) {if (n < size()) {_finish = _start + n;}else{reserve(n);}
}

运算符重载接口:

  • operator[]:通过下标访问 vector 中的元素。
T& operator[](size_t n) {assert(_start && n>=0);return _start[n];
}
  • operator<<operator>>:重载输入输出运算符,方便对 vector 进行输入输出操作。
std::ostream& operator<<(std::ostream& os, const my::vector<T>& v) {for (auto it = v.begin(); it != v.end(); ++it) {if (it != v.begin()) os << " ";  // 保证空格分隔if constexpr (has_output_operator<T>::value) {os << *it;}else {os << typeid(T).name() << "@" << &*it;}}return os;
}
friend std::istream& operator >> (std::istream& is, vector<T>& v) {T x = 0;while (is >> x) {if (v._finish == v._end_of_storage)v.reserve(2 * v.capacity());v.push_back(x);}return is;
}

👨💻 vector接口实战演练

  • 🎯测试函数
void test_constructors() {// 初始化列表构造测试my::vector<int> v1{ 7, 28, 1987 };assert(v1.size() == 3 && v1[0] == 7 && v1[2] == 1987);// 拷贝构造函数测试my::vector<int> v2 = v1;assert(v2.size() == 3 && v2.capacity() == 3);v2.push_back(2023);assert(v1.size() != v2.size()); // 验证深拷贝
}
  • 🧪 插入删除测试
void test_capacity_management() {my::vector<std::string> v;// 🧪 容量增长测试assert(v.capacity() == 0);v.push_back("Hello");assert(v.capacity() == 4);    // ✅ 初始扩容策略验证for (int i = 0; i < 10; ++i) v.push_back("World");assert(v.capacity() == 16);   // ✅ 2倍扩容验证
}
void test_element_operations() {my::vector<int> v{ 5,3,1 };// ✅ 正常插入操作测试v.insert(1, 999);         // [5,999,3,1]assert(v.size() == 4 && v[1] == 999);// ✅ 迭代器删除测试auto it = v.erase(v.begin() + 2); // 删除索引2(值3)assert(*it == 1 && v.size() == 3);// ✅ 迭代器失效测试my::vector<int> v2{ 1,2,3 };auto old_cap = v2.capacity();auto beg = v2.begin();v2.insert(1, 5); // 触发扩容assert(old_cap < v2.capacity() && "Capacity should increase");try {*beg = 10;   // ⚠️ 旧迭代器应失效assert(false);}catch (...) {}    // 实际可能崩溃而非抛异常
}

性能优化关键

操作时间(1k次)内存波动
push_back12ms阶梯式增长
insert(0)356ms频繁扩容
erase末尾3ms无变化

知识卡片📌 reserve预分配可减少87%扩容开销</知识卡片>

常见问题避坑
⚠️ 迭代器失效问题

- vector<int> v{1,2,3};
- auto it = v.begin();
- v.push_back(4);  // 可能导致迭代器失效
+ size_t idx = it - v.begin();  // 改用偏移量
+ v.push_back(4);
+ it = v.begin() + idx;

⚠️ 深浅拷贝陷阱

// 错误示例:直接复制指针
vector(const vector& v) {_start = v._start;  // 导致双杀问题
}
// 正确实现:深拷贝
vector(const vector& v) {reserve(v.size());std::copy(v.begin(), v.end(), _start);
}

http://www.mrgr.cn/news/92035.html

相关文章:

  • MySQL 入门大全:运算符
  • 蓝桥杯训练题目(一)—— 难度:简单(除了最后一题哈)
  • 20250223下载并制作RTX2080Ti显卡的显存的测试工具mats
  • C语言图结构学习笔记
  • 小波变换背景预测matlab和python样例
  • 进程的替换
  • C进阶 自定义类型
  • 2025教育与科研领域实战全解析:DeepSeek赋能细分场景深度指南(附全流程案例与资源)
  • SpringBoot+Vue+Mysql苍穹外卖
  • 大数据学习之PB级音乐数据中心数仓综合项目(1)-理论知识和项目需求、歌曲热度与歌手热度排行
  • C++:pthread的使用
  • 【Linux】: 传输层协议 TCP
  • Springboot 高频面试题
  • 【洛谷排序算法】P1012拼数-详细讲解
  • 虚拟dom 真实dom
  • ASP.NET Core Clean Architecture
  • Spring Boot 概要(官网文档解读)
  • 我们来学人工智能 -- DeepSeek客户端
  • FPGA DSP:Vivado 中带有 DDS 的 FIR 滤波器
  • 高等数学(上)题型笔记(六)定积分的应用