创建和添加

std::vector 保存连续的一组元素,可以从空容器开始,再使用 push_back 添加数据。初始化列表适合数据已知的场景。

#include <vector>

std::vector<int> scores{95, 88, 92};
scores.push_back(90);
scores.emplace_back(86);

push_back 接收一个已经构造好的对象,emplace_back 在容器尾部直接构造对象。对基础类型,两者的结果相同。

访问元素

下标运算符适合已经确认索引有效的代码。at 会进行边界检查,索引无效时抛出 std::out_of_range。

if (!scores.empty()) {
  std::cout << scores.front() << '\n';
  std::cout << scores[1] << '\n';
  std::cout << scores.at(2) << '\n';
  std::cout << scores.back() << '\n';
}

empty 用于判断容器是否有元素。读取 front、back 或任何下标前,应先保证容器不为空并确认索引范围。

大小和容量

size 表示当前元素数量,capacity 表示已经分配的存储空间。添加元素时,如果当前容量不足,容器会申请一块更大的连续空间并移动元素。

std::vector<int> values;
values.reserve(100);

std::cout << values.size() << '\n';
std::cout << values.capacity() << '\n';
reserve 只改变容量,不改变元素数量。resize 会改变元素数量,并为新增位置创建默认值。

插入和迭代器失效

在中间位置插入或删除元素时,后续元素会移动。发生重新分配后,原有指针、引用和迭代器都可能失效。

auto position = scores.begin() + 1;
scores.insert(position, 100);
// position 可能已经失效

需要继续访问容器时,在修改操作完成后重新获取迭代器。保存元素地址时,先确认后续操作不会触发扩容。

边界处理

遍历容器时优先使用范围 for。需要索引时,循环条件使用 index < scores.size(),并注意 size 返回无符号整数。

for (const auto& score : scores) {
  std::cout << score << '\n';
}

try {
  std::cout << scores.at(5) << '\n';
} catch (const std::out_of_range& error) {
  std::cerr << error.what() << '\n';
}

练习可以加入空容器、单个元素和超过当前长度的索引,分别观察 operator[] 与 at 的行为。

下一篇,C / C++ 编译、调试和查询工具 返回文章列表