C++ 数据结构之std::vector介绍

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在秋名山》,欢迎大家关注~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux在秋名山

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值