std::vector
与数组类似,但它更加智能,能自动管理内存大小。
假设你要处理用户上传的Excel数据,行数可能从几十到几万行不等——这时用固定大小的数组会捉襟见肘,而使用std::vector
就能游刃有余。
关键特性速览
- 动态伸缩:容量不够时自动扩容
- 快速访问:通过下标直接访问元素,时间复杂度O(1)
- 内存连续:数据在内存中紧密排列,这对缓存机制非常友好
核心操作
基础三板斧
#include <iostream>
#include <vector>
int main() {
// 创建与初始化
std::vector<int> primes = {0, 1, 2, 3, 4, 5, 6}; // 直接初始化
std::vector<std::string> names; // 空容器
// 增删元素
primes.push_back(7); // 尾部追加
primes.pop_back(); // 删除末尾
// 随机访问
std::cout << primes[0] << std::endl; // 输出0(不检查越界)
std::cout << primes.at(6) << std::endl; // 输出6(越界会抛出异常)
}
进阶操作
当需要处理游戏中的动态对象时,可以这样操作:
#include <iostream>
#include <vector>
#include <algorithm>
struct Enemy {
std::string name;
int health;
Enemy(std::string name_, int health_) {
name = name_;
health = health_;
}
};
int main() {
std::vector<Enemy> enemies;
// 新敌人出现
enemies.emplace_back("Zombie_0", 80); // 直接构造更高效
enemies.emplace_back("Zombie_1", 90);
enemies.emplace_back("Zombie_2", 100);
// 击杀敌人
enemies[0].health = 0;
enemies[2].health = 0;
// 处理阵亡敌人 (注意erase-remove惯用法)
auto it = remove_if(enemies.begin(), enemies.end(),
[](const Enemy& e) { return e.health <= 0; });
enemies.erase(it, enemies.end());
return 0;
}
性能优化
1. 预分配空间
当知道大概元素数量时,提前预留空间:
std::vector<SensorData> data;
data.reserve(5000); // 避免插入时的多次扩容
2. 选择正确的构造方式
// 传统方式:先构造再拷贝
objects.push_back(MyClass(param1, param2));
// 优化方式:原地构造
objects.emplace_back(param1, param2); // 省去临时对象拷贝
3. 高效删除技巧
需要删除中间元素时,如果不在乎顺序,可以交换位置后删除末尾:
std::swap(v[index], v.back()); // 把要删的元素换到最后
v.pop_back(); // 此时删除成本最低
如果需要保持顺序,那么可以使用erase
:
v.erase(v.begin() + index);
4. 利用现代C++特性
移动语义能大幅提升效率:
std::vector<std::string> buffer;
std::string large_data = fetch_data(); // 假设这是个很大的字符串
buffer.push_back(std::move(large_data)); // 转移所有权而非复制
避坑指南
误区1:盲目使用[]
操作符
std::vector<int> v = {1, 2, 3};
std:cout << v[5] << std::endl; // 越界访问!
建议在不确定时使用at()
方法,虽然慢一点但安全:
try {
std::cout << v.at(5) << std::endl; // 会抛出out_of_range异常
} catch(const std::exception& e) {
std::cerr << "访问越界:" << e.what() << std::endl;
}
误区2:在循环中反复扩容
// 低效写法
std::vector<Matrix> matrices;
for(int i = 0; i < 10000; i++) {
matrices.push_back(create_matrix()); // 可能多次触发扩容
}
// 优化写法
matrices.reserve(10000); // 一次性预留空间
for(int i = 0; i < 10000; i++) {
matrices.push_back(create_matrix());
}
误区3:忽视迭代器失效问题
std::vector<int> nums = {1, 2, 3, 4, 5};
auto it = nums.begin();
while(it != nums.end()) {
if(*it % 2 == 0){
nums.erase(it); // 错误!erase后迭代器失效
// 应该用 it = nums.erase(it);
} else {
it++;
}
}
总结
对于std::vector
的介绍就到这里了,下次遇到需要动态数组的时候,不妨先考虑它,再根据具体需求调整策略。
希望本文对你有帮助!
本文首发于微信公众号《Linux在秋名山》,欢迎大家关注~