跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

C++ STL 容器 vector 详解:定义、访问与操作

C++ STL vector 是序列容器,支持运行时动态插入和删除元素,基于数组实现但自动管理内存。介绍 vector 的定义与初始化方式,对比 at、operator[] 和迭代器三种访问方法的特性与安全性,解析 push_back、emplace_back 及 insert 的插入机制与性能差异,阐明 reserve 与 resize 在容量与大小控制上的不同,说明 assign 函数的三种形式及内存变化规则,最后分析迭代器失效的本质原因及常见触发场景。

女王发布于 2026/3/15更新于 2026/4/2512 浏览

C++ STL 容器 vector 详解

1. 定义 vector

C++ 中的 vector 是一种序列容器,允许在运行时动态地插入和删除元素。它是基于数组的数据结构,但能自动管理内存,无需手动分配和释放。

#include <vector>

// 创建一个存储整数的空 vector
std::vector<int> myVector;

// 初始化包含元素的 vector
std::vector<int> myVector = {1, 2, 3, 4, 5};

// 创建一个包含 5 个整数的 vector,每个值都为默认值(0)
std::vector<int> myVector(5);

// 创建一个包含 5 个整数的 vector,每个值都为 10
std::vector<int> myVector(5, 10);

2. 访问 vector 中的元素

int main() {
    // 初始化一个 vector(元素类型 int,初始值 [10, 20, 30, 40, 50],索引 0~4)
    std::vector<int> vec = {10, 20, 30, 40, 50};
    std::cout << "原始 vector:";
    for (int& val : vec) {
        std::cout << val << " ";
    }
}

2.1 at 访问

at() 成员函数提供安全访问,带边界检查。

  • 语法:vec.at(index)
  • 特点:会检查索引是否越界,越界时抛出 std::out_of_range 异常;效率略低于 []。
int main() {
    std::vector<int> vec = {10, 20, 30, 40, 50};
    std::cout << "原始 vector:";
    for (int& val : vec) std::cout << val << " ";
    std::cout << "\n=== at() 安全访问 ===" << std::endl;

    // 1. 读取元素
    std::cout << "索引 2 的元素:" << vec.at(2) << std::endl; // 输出 30

    // 2. 修改元素(返回引用,支持读写)
    vec.at(3) = 400; // 将索引 3 的元素从 40 改为 400
    std::cout << "修改后 vector:";
    for (int& val : vec) std::cout << val << " ";
    std::cout << std::endl;

    // 3. 越界访问(抛出异常,可捕获)
    try {
        vec.at(10); // 索引 10 超出范围,抛出异常
    } catch (const std::out_of_range& e) {
        std::cout << "at() 越界错误:" << e.what() << std::endl;
    }
}

2.2 operator[] 访问

[] 下标运算符最常用,效率最高。

  • 语法:vec[index](索引从 0 开始)
  • 特点:直接内存访问,执行效率最佳;但不进行边界检查,越界访问可能引发未定义行为(程序崩溃或内存污染)。
int main() {
    std::vector<int> vec = {10, 20, 30, 40, 50};
    std::cout << "原始 vector:";
    for (int& val : vec) std::cout << val << " ";
    std::cout << "\n=== [] 下标访问 ===" << std::endl;

    // 1. 读取元素
    std::cout << "索引 0 的元素:" << vec[0] << std::endl; // 输出 10
    std::cout << "索引 3 的元素:" << vec[3] << std::endl; // 输出 40

    // 2. 修改元素(返回引用,支持读写)
    vec[1] = 200; // 将索引 1 的元素从 20 改为 200
    vec[4] = 500; // 将索引 4 的元素从 50 改为 500
    std::cout << "修改后 vector:";
    for (int val : vec) std::cout << val << " ";
    std::cout << std::endl;

    // 3. 注意:越界访问(危险!未定义行为)
    // vec[10] = 999; // 索引 10 超出范围(0~4),可能崩溃,编译器不报错
}

2.3 迭代器访问

2.3.1 普通迭代器
int main() {
    std::vector<int> vec = {10, 20, 30, 40, 50};
    std::cout << "原始 vector:";
    for (int& val : vec) std::cout << val << " ";
    std::cout << "\n=== 普通迭代器(可读写) ===" << std::endl;

    std::vector<int>::iterator it = vec.begin(); // it 指向第一个元素(10)
    for (; it != vec.end(); ++it) {
        std::cout << *it << std::endl;
    }
    std::cout << std::endl;

    it = vec.begin();
    for (; it != vec.end(); ++it) {
        *it += 10;
        std::cout << *it << std::endl;
    }
    return 0;
}
2.3.2 常性迭代器

只可读元素,不可以修改值。

int main() {
    std::vector<int> vec = {10, 20, 30, 40, 50};
    std::cout << "原始 vector:";
    for (int& val : vec) std::cout << val << " ";
    std::cout << "\nconst 迭代器遍历(只读):" << std::endl;

    std::vector<int>::const_iterator cit = vec.cbegin(); // cbegin() 返回 const 迭代器
    for (; cit != vec.cend(); ++cit) {
        std::cout << *cit << " "; // 正常读取
        // *cit = 0; // 编译错误:const 迭代器禁止修改元素
    }
    std::cout << std::endl;
    return 0;
}
2.3.3 逆置迭代器

使用 rbegin() 和 rend() 可以获取反向迭代器,用于从后向前遍历。

2.4 at 和 operator[] 的区别

  • at() 安全但稍慢,适合需要边界检查的场景。
  • [] 快速但不安全,适合已知索引合法的高频场景。

3. 插入元素到 vector

3.1 push_back

向尾部插入元素。若插入前没有可用空间,需先扩容(通常原容量的 1.5 倍~2 倍),并将原数组所有元素拷贝/移动到新的内存。

  • 拷贝构造:创建临时副本对象,通过定位 new 构造在 vector 空间。
  • 移动构造:将对象资源直接转移到 vector 空间。

建议在使用 push_back 前调用 reserve 预留空间,避免频繁扩容。

3.2 emplace_back

解决频繁拷贝和移动资源的问题,又称原位构造。直接在 vector 空间上构造对象,避免临时对象的创建。

3.3 insert

在指定位置插入元素。

// 插入单个元素
iterator insert(iterator pos, const T& value);
iterator insert(iterator pos, T&& value); // C++11 移动语义

// 插入多个相同元素
iterator insert(iterator pos, size_t count, const T& value);

// 插入元素区间
template <class InputIt>
iterator insert(iterator pos, InputIt first, InputIt last);

3.4 emplace_back 和 push_back 区别

  • push_back:先构造临时对象,再移动/拷贝进容器。
  • emplace_back:直接将参数传递给构造函数,原地构造。
#include <vector>
#include <string>
using namespace std;

class Person {
public:
    Person(string name, int age) : name_(name), age_(age) {}
private:
    string name_;
    int age_;
};

int main() {
    vector<Person> v;
    // push_back:先构造临时 Person,再移动到 vector
    v.push_back(Person("Alice", 20));
    // emplace_back:直接在 vector 尾部原地构造 Person
    v.emplace_back("Bob", 22);
    return 0;
}

4. reserve 和 resize

  • reserve(n):预分配至少 n 个元素的存储空间,不改变 size,仅增加 capacity。
  • resize(n):改变容器大小。若新大小大于当前大小,新增元素默认初始化;若小于,则销毁多余元素。
vector<int> vec{1, 2, 3};
vec.reserve(10);
std::cout << vec.size();   // 输出 3(元素数量不变)
std::cout << vec.capacity(); // 输出 10(内存已预分配)

vector<int> vec2{1, 2, 3};
vec2.resize(5); // 新增 2 个元素,默认值为 0 → vec = {1, 2, 3, 0, 0}
std::cout << vec2.size();   // 输出 5
std::cout << vec2.capacity(); // 输出 ≥5

vec2.resize(2); // 销毁后 3 个元素 → vec = {1, 2}
std::cout << vec2.size();   // 输出 2

5. assign

assign() 用于替换容器中的所有现有元素(先清空原有元素,再插入新元素)。它会直接改变 vector 的 size,并在新元素数量超过当前容量时调整 capacity。

形式 1:assign(n, val)

vector<int> vec{1, 2, 3}; // 原内容:{1, 2, 3}
vec.assign(4, 10);        // 清空原元素 → 插入 4 个 10
// 结果:vec = {10, 10, 10, 10},size=4,capacity≥4

形式 2:assign(first, last)

vector<int> vec{1, 2, 3};
int arr[] = {100, 200, 300, 400};
vec.assign(arr + 1, arr + 3); // 插入数组中 arr+1 到 arr+3 的元素(200、300)
// 结果:vec = {200, 300}

vector<int> tmp{5, 6, 7};
vec.assign(tmp.begin(), tmp.end()); // 从另一个 vector 导入
// 结果:vec = {5, 6, 7}

形式 3:assign(initializer_list)

vector<int> vec{1, 2, 3};
vec.assign({8, 9, 10, 11}); // 清空原元素 → 插入 8、9、10、11
// 结果:vec = {8, 9, 10, 11},size=4,capacity≥4

特殊情况

  • 内存变化:自动扩容(当新元素数量 > 当前 capacity),不会主动缩容(如原 capacity=10,assign(2, 0) 后 capacity 仍为 10)。
  • 元素析构:对于类对象,assign() 会先调用所有原有元素的析构函数,再构造新元素。
  • n=0 时:assign(0, val) 等价于清空 vector(size=0),但 capacity 不变(需使用 shrink_to_fit() 释放内存)。
vec.assign(0, 0); // 清空所有元素,size=0,capacity 不变

6. 迭代器失效

6.1 迭代器失效本质

迭代器本质是'容器元素的内存指针 / 索引封装'。当容器底层内存布局改变(如扩容、元素移动)、元素被删除时,迭代器指向的地址 / 逻辑位置失效,此时解引用或操作迭代器会导致 UB(未定义行为)。

6.2 迭代器失效场景

  • 对 vector 进行插入操作(push_back, insert)可能导致扩容,使所有迭代器失效。
  • 对 vector 进行删除操作(erase)导致元素移动,使被删除位置及之后的迭代器失效。
  • 对 vector 进行 resize 操作可能导致内存重新分配,使所有迭代器失效。

目录

  1. C++ STL 容器 vector 详解
  2. 1. 定义 vector
  3. 2. 访问 vector 中的元素
  4. 2.1 at 访问
  5. 2.2 operator[] 访问
  6. 2.3 迭代器访问
  7. 2.3.1 普通迭代器
  8. 2.3.2 常性迭代器
  9. 2.3.3 逆置迭代器
  10. 2.4 at 和 operator[] 的区别
  11. 3. 插入元素到 vector
  12. 3.1 push_back
  13. 3.2 emplace_back
  14. 3.3 insert
  15. 3.4 emplaceback 和 pushback 区别
  16. 4. reserve 和 resize
  17. 5. assign
  18. 形式 1:assign(n, val)
  19. 形式 2:assign(first, last)
  20. 形式 3:assign(initializer_list)
  21. 特殊情况
  22. 6. 迭代器失效
  23. 6.1 迭代器失效本质
  24. 6.2 迭代器失效场景
  • 💰 8折买阿里云服务器限时8折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 栈和队列数据结构初阶:模拟实现与 STL 应用
  • Linux 进程池实战:基于管道通信的任务分发系统实现
  • 基于 Python+Vue3+Django 的高校校友信息管理系统设计与开发
  • FastAPI:Python 高性能 Web 框架深度解析
  • Flutter 三方库 webkit_inspection_protocol 的鸿蒙化适配指南
  • 基于 ComfyUI 与 AnimateDiff 的 30 秒人物成长 AI 视频制作教程
  • 黑客入门指南:零基础掌握五项核心能力
  • Java 全栈开发工程师面试技术问答:从基础到进阶
  • C/C++回调函数用法详解
  • 百瑞互联 BR8654 蓝牙 6.0 SOC 芯片特性与参数
  • Coze + Bot API:实现带自我反思的高质量长文翻译 Agent
  • Android 逆向:在 Unidbg 中解决 native 函数内调用 Java 方法的报错
  • Code Llama 7B 模型完整使用指南
  • 基于 Nexent 打造 AI 烹饪顾问:知识库与 MCP 生态实战
  • OpenClaw 安全风险全解析:AI 助手部署中的权限与数据隐患
  • 电商系统商品管理模块设计与实现(AI 辅助)
  • WebSite-Downloader 网站整站下载工具使用指南
  • Python 网络爬虫技术详解:原理、实战与最佳实践
  • LLaMA Factory 数据集配置格式说明
  • Xcode 真机调试报错:Developer Disk Image 无法卸载

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online