C++中std::vector使用超级详解

一、std::vector 简介

std::vector 是 C++ STL 中最常用的动态数组容器,特点是:

  • 支持 随机访问
  • 内存是 一块连续的空间
  • 自动扩容,支持添加和删除元素
#include <vector>
#include <iostream>

二、常见用法

1. 初始化

std::vector<int> v1;                    // 空向量
std::vector<int> v2(5);                 // 5 个默认值为 0 的元素
std::vector<int> v3(5, -1);             // 5 个值为 -1 的元素
std::vector<int> v4 = {1, 2, 3, 4};     // 初始化列表

2. 添加元素

v1.push_back(10);   // 添加一个元素到末尾

3. 遍历元素

for (size_t i = 0; i < v1.size(); ++i)
    std::cout << v1[i] << " ";

for (int x : v1)
    std::cout << x << " ";

for (auto it = v1.begin(); it != v1.end(); ++it)
    std::cout << *it << " ";

4. 常用操作

v1.size();            // 当前元素个数
v1.empty();           // 是否为空
v1.clear();           // 清空所有元素
v1.back();            // 返回最后一个元素
v1.front();           // 返回第一个元素

三、resize() vs reserve() 的区别

函数作用影响大小影响容量初始化元素
resize(n)直接改变 size,增大时会初始化元素✅ 默认值
reserve(n)预留容量,不改变 size,不初始化元素
std::vector<int> v;

v.reserve(5);   // 容量变为5,但 size 还是0
v.resize(3);    // 现在 size 变为3,初始化3个元素

四、性能分析

1. 添加元素性能

std::vector<int> v;
for (int i = 0; i < 1e6; ++i) {
    v.push_back(i);  // 会不断扩容(通常以 2 倍增长)
}
  • 每次扩容会分配新内存并拷贝旧数据
  • 为避免频繁扩容,可提前 reserve(n)

2. 与 std::deque 比较

操作vectordeque
push_back✅ 快✅ 快
push_front❌ 非常慢✅ 快
随机访问✅ 高效(连续内存)✅ 稍慢(分块)
遍历性能✅ 最优❌ 缓存命中较差

3. 与 std::list 比较

操作vectorlist
随机访问✅ 支持❌ 不支持
中间插入❌ 慢(移动元素)✅ 快(常数时间)
遍历性能✅ 好❌ 差(非局部访问)

五、注意事项

注意点建议
内存连续不要随意返回 vectordata() 指针给外部长期持有
插入性能插入大量数据前建议 reserve()
指针/引用失效扩容时旧地址会失效
resize() 构造新对象对类对象注意构造/析构成本
push_back 后地址失效扩容时原指针、引用都失效!避免用裸指针
频繁插入中间位置慢插入/删除中间元素为 O(n),性能差
clear() 不回收内存清空元素但不会减少容量
shrink_to_fit() 不可靠提交释放容量,但具体行为平台相关

指针失效示例

std::vector<int> v = {1, 2, 3};
int* ptr = &v[0];
v.push_back(4);  // 如果扩容,ptr 可能失效!

六、综合使用示例

1. 保存类对象

struct Point {
    float x, y;
};

std::vector<Point> points;
points.emplace_back(1.0f, 2.0f);

2. 用作二维数组

std::vector<std::vector<int>> matrix(3, std::vector<int>(4, 0));
// 3 行 4 列,全部初始化为 0

3. 与 std::shared_ptr 配合

std::vector<std::shared_ptr<Point>> vec;
vec.push_back(std::make_shared<Point>());

4. 使用 std::move 提高性能:

std::vector<std::string> v;
std::string s = "hello";
v.push_back(std::move(s)); // 避免拷贝

5. 使用 std::vector<bool> 的陷阱:

  • 它是位压缩优化版,不是普通的 bool 数组
  • 有时会导致不能获取引用/指针

建议避免使用它,或用 std::vector<char> 替代。

6. 快速可视化 sizecapacity 增长

std::vector<int> v;
for (int i = 0; i < 100; ++i) {
    v.push_back(i);
    std::cout << "Size: " << v.size()
              << ", Capacity: " << v.capacity() << std::endl;
}

7. 固定长度数组的模拟:

std::vector<int> data(100, 0);  // 100 个元素,初始为0

8. 避免重复分配:

std::vector<std::string> names;
names.reserve(1000);
for (...) {
    names.emplace_back(...);  // 高效
}

std::vector 是一个自动管理内存的容器,但它的内存释放行为可能不是你预期的:即使你调用了 clear(),它也不会释放 capacity 对应的内存


七、std::vector对象内存释放

std::vector 常见的释放方式总结如下。

方法作用内存是否释放
clear()清除所有元素❌ 不释放内存(capacity 保留)
shrink_to_fit()请求释放多余内存✅ 释放未使用容量(非强制)
swap()与空 vector 交换,强制释放✅✅ 推荐方式
std::vector<T>().swap(vec)简写版强制释放✅✅ 推荐方式

示例演示

示例 1:clear() 不释放内存
std::vector<int> v(10000);
std::cout << "Before clear: size = " << v.size()
          << ", capacity = " << v.capacity() << "\n";

v.clear();

std::cout << "After clear: size = " << v.size()
          << ", capacity = " << v.capacity() << "\n";

输出可能是:

Before clear: size = 10000, capacity = 10000
After clear: size = 0, capacity = 10000

示例 2:推荐做法 — 与空 vector 交换
std::vector<int> v(10000);
std::vector<int>().swap(v); // 强制释放所有内存

// v.size() == 0, v.capacity() == 0

示例 3:使用 shrink_to_fit()
std::vector<int> v(10000);
v.clear();
v.shrink_to_fit(); // 请求释放 capacity,但不是强制的

注意:shrink_to_fit()non-binding request,标准库实现可以选择忽略这个请求。


总结建议

目标推荐操作
清除数据,但保留内存用于重用clear()
清除数据 + 建议释放内存clear(); shrink_to_fit();
清除数据 + 强制释放所有内存std::vector<T>().swap(vec);

高级应用建议

  • 在循环中避免反复构造销毁大 vector,建议:vec.clear(); + reserve(n); 预分配
  • 如果 vector 是类成员,析构中使用 swap 强制释放空间更彻底
  • 用于缓存图像帧 / 点云数据时,vector.swap() 能快速释放大块内存

八、小结

特性结论
内存模型连续
访问方式支持随机访问
插入效率后端高效,中间慢
替代容器建议若需头部插入:用 deque;频繁中间操作:用 list
调优建议reserve() 可提升性能;避免频繁扩容
连续内存,兼容 C 数组中间插入慢,扩容成本高
标准接口统一需要手动管理扩容策略
Eigen、OpenCV cv::Mat 等兼容性高无法支持双端插入
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

点云SLAM

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

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

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

打赏作者

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

抵扣说明:

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

余额充值