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

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

文章目录

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. 深拷贝处理:

    cpp 复制代码
    // 拷贝构造函数示例
    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*

关键组件实现:

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

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

cpp 复制代码
	//部分构造
	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 对象占用的资源。

cpp 复制代码
	~vector() {
		if (_start) {
			clear();
		}
		_start = _finish = _end_of_storage = nullptr;
	}

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

容量管理接口:

  • reserve:预留指定容量的存储空间。
cpp 复制代码
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 的容量。
cpp 复制代码
		//容器总容量
size_t capacity() {
	return _end_of_storage - _start;
}
  • size:返回当前 vector 中元素的数量。
cpp 复制代码
size_t size()const {
   return _finish - _start;
}
  • rest_size:返回当前 vector 剩余的可存储元素的空间大小。
cpp 复制代码
size_t rest_size() {
   	return capacity() - size();
}

迭代器接口:

  • begin 和 end:返回指向 vector 首元素和尾后元素的迭代器。
cpp 复制代码
		//首元素
		iterator begin() {
			return _start;
		}

		//有效尾元素
		iterator end() {
			return _finish;
		}

		const_iterator begin() const {
			return _start;
		}

		const_iterator end() const {
			return _finish;
		}

元素操作接口:

  • push_back:在 vector 尾部插入一个元素。
cpp 复制代码
void push_back(const T& v) {
	if (_finish == _end_of_storage) {
		reserve(capacity() == 0 ? 4 : 2 * size());
	}
	*_finish = v;
	++_finish;
}
  • insert:在指定位置插入一个元素。
cpp 复制代码
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:删除指定位置的元素。
cpp 复制代码
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 中的所有元素。
cpp 复制代码
void clear() {
	for (auto it = _start; it != _end_of_storage; ++it) {
		it->~T();
	}
	_start = _finish;
}

查找和调整大小接口:

  • find:查找指定元素在 vector 中的位置。
cpp 复制代码
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 的大小。
cpp 复制代码
void resize(size_t n) {
   if (n < size()) {
   	_finish = _start + n;
   }
   else{
   	reserve(n);
   }
}

运算符重载接口:

  • operator[]:通过下标访问 vector 中的元素。
cpp 复制代码
T& operator[](size_t n) {
   assert(_start && n>=0);

   return _start[n];
}
  • operator<<operator>>:重载输入输出运算符,方便对 vector 进行输入输出操作。
cpp 复制代码
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;
}
cpp 复制代码
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接口实战演练

  • 🎯测试函数
cpp 复制代码
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()); // 验证深拷贝
}
  • 🧪 插入删除测试
cpp 复制代码
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倍扩容验证
}
cpp 复制代码
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_back 12ms 阶梯式增长
insert(0) 356ms 频繁扩容
erase末尾 3ms 无变化

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

常见问题避坑

⚠️ 迭代器失效问题

diff 复制代码
- 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;

⚠️ 深浅拷贝陷阱

cpp 复制代码
// 错误示例:直接复制指针
vector(const vector& v) {
    _start = v._start;  // 导致双杀问题
}
// 正确实现:深拷贝
vector(const vector& v) {
    reserve(v.size());
    std::copy(v.begin(), v.end(), _start);
}
相关推荐
CoderIsArt3 分钟前
生成一个立方体贴图(Cube Map)
算法·sharpgl
且听风吟ayan9 分钟前
leetcode day20 滑动窗口209+904
算法·leetcode·c#
m0_675988239 分钟前
Leetcode350:两个数组的交集 II
算法·leetcode·数组·哈希表·python3
_Itachi__10 分钟前
LeetCode 热题 100 160. 相交链表
算法·leetcode·链表
m0_6759882313 分钟前
Leetcode1206:设计跳表
算法·leetcode·跳表·python3
冠位观测者14 分钟前
【Leetcode 每日一题 - 扩展】1512. 好数对的数目
数据结构·算法·leetcode
Joyner201814 分钟前
python-leetcode-路径总和 III
算法·leetcode·职场和发展
南宫生15 分钟前
力扣每日一题【算法学习day.133】
java·学习·算法·leetcode
_Itachi__16 分钟前
LeetCode 热题 100 560. 和为 K 的子数组
数据结构·算法·leetcode
夏末秋也凉16 分钟前
力扣-贪心-55 跳跃游戏
算法·leetcode·游戏