【C++指南】vector(一):从入门到详解

.
💓 博客主页:倔强的石头的CSDN主页
📝Gitee主页:倔强的石头的gitee主页
⏩ 文章专栏:《C++指南》
期待您的关注

文章目录

    • 一、默认成员函数
      • [1. 默认构造函数](#1. 默认构造函数)
      • [2. 元素数量构造函数](#2. 元素数量构造函数)
      • [3. 迭代器范围构造函数](#3. 迭代器范围构造函数)
      • [4. 初始化列表构造函数(C++11 起)](#4. 初始化列表构造函数(C++11 起))
      • [5. 拷贝构造函数与赋值运算符](#5. 拷贝构造函数与赋值运算符)
    • 二、迭代器相关函数
      • [1. 基础迭代器](#1. 基础迭代器)
      • [2. 常量迭代器(C++11 起)](#2. 常量迭代器(C++11 起))
    • 三、容量管理函数
      • [1. 容量与大小控制](#1. 容量与大小控制)
      • [2. 动态调整函数](#2. 动态调整函数)
        • [`resize(n, val)` vs `resize(n)`](#resize(n, val) vs resize(n))
        • [`reserve(n)` vs `shrink_to_fit()`](#reserve(n) vs shrink_to_fit())
    • 四、元素访问函数
      • [1. 下标访问与安全访问](#1. 下标访问与安全访问)
      • [2. 首尾元素访问](#2. 首尾元素访问)
      • [3. 底层数据指针 `data()`](#3. 底层数据指针 data())
    • 五、修改操作函数
      • [1. 尾部操作](#1. 尾部操作)
      • [2. 插入与删除](#2. 插入与删除)
        • [`insert` 的多个重载版本](#insert 的多个重载版本)
        • [`erase` 的用法](#erase 的用法)
      • [3. 内容替换与清空](#3. 内容替换与清空)
    • 六、使用建议和注意事项

std::vector 是 C++ STL 中最核心的动态数组容器,支持高效随机访问和动态扩容。本文从 基础用法深度优化 两个维度,系统解析其构造函数、迭代器、容量管理、元素访问和修改操作,涵盖函数重载、参数差异及相似函数对比,并提供丰富的代码示例。


一、默认成员函数

1. 默认构造函数

  • 语法vector<T> vec;

  • 行为:创建空容器,容量为 0,不分配内存。

  • 示例

    cpp 复制代码
    std::vector<int> vec; // 空 vector

2. 元素数量构造函数

  • 语法vector<T> vec(n, val);

  • 行为

    • vector<T> vec(n):创建包含 n 个默认初始化元素的容器(如 int 初始化为 0)。
    • vector<T> vec(n, val):创建包含 n 个值为 val 的元素的容器。
  • 示例

    cpp 复制代码
    std::vector<int> vec1(5);     // {0, 0, 0, 0, 0}
    std::vector<int> vec2(3, 10); // {10, 10, 10}

3. 迭代器范围构造函数

  • 语法vector<T> vec(iter_start, iter_end);

  • 行为 :用其他容器的迭代器范围初始化 vector

  • 示例

    cpp 复制代码
    std::list<int> lst = {1, 2, 3};
    std::vector<int> vec(lst.begin(), lst.end()); // {1, 2, 3}

4. 初始化列表构造函数(C++11 起)

  • 语法vector<T> vec{1, 2, 3};

  • 行为:直接通过列表初始化元素。

  • 示例

    cpp 复制代码
    std::vector<int> vec = {4, 5, 6}; // {4, 5, 6}

5. 拷贝构造函数与赋值运算符

  • 语法

    cpp 复制代码
    vector<T> vec2(vec1); // 拷贝构造
    vec2 = vec1;          // 赋值运算符
  • 行为:深拷贝容器内容,新旧容器完全独立。

  • 示例

    cpp 复制代码
    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2(vec1); // 拷贝构造
    vec2 = vec1;                // 赋值操作

二、迭代器相关函数

1. 基础迭代器

函数 功能 示例
begin() 返回指向第一个元素的迭代器 auto it = vec.begin();
end() 返回指向末尾(最后一个元素之后)的迭代器 for (auto it = vec.begin(); it != vec.end(); ++it)
rbegin() 返回反向迭代器(从末尾开始遍历) auto rit = vec.rbegin();
rend() 返回反向迭代器的结束位置 while (rit != vec.rend())

2. 常量迭代器(C++11 起)

函数 功能 示例
cbegin() 返回常量正向迭代器 auto cit = vec.cbegin();
cend() 返回常量正向迭代器的结束位置 for (; cit != vec.cend(); ++cit)
crbegin() 返回常量反向迭代器 auto crit = vec.crbegin();
crend() 返回常量反向迭代器的结束位置 while (crit != vec.crend())

示例

cpp 复制代码
std::vector<int> vec = {10, 20, 30};
// 正向遍历
for (auto it = vec.begin(); it != vec.end(); ++it) {
    std::cout << *it << " "; // 输出:10 20 30
}
// 常量反向遍历
for (auto crit = vec.crbegin(); crit != vec.crend(); ++crit) {
    std::cout << *crit << " "; // 输出:30 20 10
}

三、容量管理函数

1. 容量与大小控制

函数 功能 示例
size() 返回当前元素数量 int n = vec.size();
capacity() 返回已分配的内存容量 int cap = vec.capacity();
empty() 检查容器是否为空 if (vec.empty()) { ... }

2. 动态调整函数

resize(n, val) vs resize(n)
  • 语法

    cpp 复制代码
    void resize(size_t n);            // 默认值填充
    void resize(size_t n, T val);     // 指定值填充
  • 行为差异

    • resize(5):若原大小为 3,新增 2 个默认值元素(如 int 为 0)。
    • resize(5, 10):新增的 2 个元素值为 10。
    • n < size(),超出部分的元素被销毁,但 容量不变
    • n>capacity(),将会引发扩容

示例

cpp 复制代码
std::vector<int> vec = {1, 2, 3};
vec.resize(5);       // {1, 2, 3, 0, 0}
vec.resize(3);       // {1, 2, 3}(容量仍可能为 5)
vec.resize(5, 10);   // {1, 2, 3, 10, 10}
reserve(n) vs shrink_to_fit()
  • reserve(n) :预分配至少 n 个元素的内存,避免频繁扩容。
  • shrink_to_fit() :请求释放未使用的内存,但 不保证容量等于 size() 。 该函数谨慎使用 因为动态申请的内存不支持分段释放,缩容实际上是开辟了新的空间,释放了原有的空间,会有一定的效率牺牲

示例

cpp 复制代码
std::vector<int> vec;
vec.reserve(100);    // 容量为 100
vec.push_back(1);
vec.shrink_to_fit(); // 容量可能变为 1(具体由实现决定)

四、元素访问函数

1. 下标访问与安全访问

特性 operator[] at()
越界检查 assert断言 有(抛出 std::out_of_range
性能 更高(直接访问) 略低(需检查)
适用场景 已知索引安全时 需要异常处理的场景

示例

cpp 复制代码
std::vector<int> vec = {10, 20, 30};
int a = vec[3];      // 未定义行为(可能崩溃或返回垃圾值)
int b = vec.at(3);   // 抛出异常:std::out_of_range

2. 首尾元素访问

函数 功能 示例
front() 访问第一个元素 vec.front() = 5;
back() 访问最后一个元素 vec.back() = 10;

对比 front()begin()

  • front() 返回元素引用,begin() 返回迭代器。
cpp 复制代码
std::vector<int> vec = {1, 2, 3};
vec.front() = 10;    // 直接修改首元素
auto it = vec.begin();
*it = 20;            // 通过迭代器修改

3. 底层数据指针 data()

  • 语法T* data();

  • 行为:返回指向底层数组的指针(C++11 起支持)。

  • 示例

    cpp 复制代码
    std::vector<int> vec = {1, 2, 3};
    int* arr = vec.data();     // 获取指针
    arr[0] = 10;              // 直接修改元素

五、修改操作函数

1. 尾部操作

函数 功能 示例
push_back(val) 在末尾添加元素(可能触发拷贝/移动) vec.push_back(4);
emplace_back(args) 直接在末尾构造元素(避免临时对象) vec.emplace_back(1, 2.0);
pop_back() 删除末尾元素 vec.pop_back();

push_back vs emplace_back

  • push_back:需构造临时对象,再拷贝或移动到容器。
  • emplace_back:直接通过参数在容器内构造对象,效率更高。

示例

cpp 复制代码
class Data {
public:
    Data(int a, double b) { /* ... */ }
};

std::vector<Data> vec;
vec.push_back(Data(1, 2.0));   // 构造临时对象,再移动
vec.emplace_back(1, 2.0);      // 直接在容器内构造

2. 插入与删除

insert 的多个重载版本
  • 语法

    cpp 复制代码
    iterator insert(iterator pos, const T& val);   // 插入单个元素
    void insert(iterator pos, size_t n, const T& val); // 插入 n 个相同元素
    void insert(iterator pos, InputIt first, InputIt last); // 插入迭代器范围
    //此范围包含 first 指向的元素,但不包含 last 指向的元素
  • 示例

    cpp 复制代码
    std::vector<int> vec = {1, 2, 3};
    vec.insert(vec.begin() + 1, 5);       // {1, 5, 2, 3}
    vec.insert(vec.begin(), 2, 10);       // {10, 10, 1, 5, 2, 3}
    std::list<int> lst = {7, 8};
    vec.insert(vec.end(), lst.begin(), lst.end()); // 末尾追加 7, 8
erase 的用法
  • 语法

    cpp 复制代码
    iterator erase(iterator pos);              // 删除单个元素
    iterator erase(iterator first, iterator last); // 删除范围元素
  • 示例

    cpp 复制代码
    std::vector<int> vec = {1, 2, 3, 4, 5};
    vec.erase(vec.begin());           // {2, 3, 4, 5}
    vec.erase(vec.begin(), vec.begin() + 2); // {4, 5}

3. 内容替换与清空

函数 功能 示例
assign 替换容器内容 vec.assign(3, 5); // {5,5,5}
clear() 清空所有元素(容量不变) vec.clear();
swap 交换两个容器的内容 vec1.swap(vec2);

assign 的重载版本

cpp 复制代码
std::vector<int> vec;
vec.assign(3, 5);                // {5, 5, 5}(填充 n 个值)
vec.assign({1, 2, 3});           // {1, 2, 3}(初始化列表)
std::list<int> lst = {7, 8};
vec.assign(lst.begin(), lst.end()); // {7, 8}(迭代器范围)

六、使用建议和注意事项

  1. 构造函数选择
    • 默认构造用 vector<T> vec;,预分配内存用 vector(n),列表初始化用 {}
  2. 容量管理
    • 频繁添加元素时优先 reserve(),可以减少频繁扩容的效率降低
  3. 元素访问
    • 安全场景用 operator[],需异常处理时用 at()
  4. 修改操作
    • 优先 emplace_back 减少拷贝,批量插入用 insert 的重载版本。
  5. 迭代器使用
    • 常量遍历用 cbegin()/cend(),反向遍历用 rbegin()/rend()

通过合理选择函数重载和参数,可以显著提升代码的效率和健壮性。

本文完

下篇文章将为读者讲解vector的底层原理和模拟实现

相关推荐
秋风&萧瑟9 分钟前
【QT】QT的多界面跳转以及界面之间传递参数
开发语言·qt
骑牛小道士11 分钟前
JAVA- 锁机制介绍 进程锁
java·开发语言
郭涤生14 分钟前
Chapter 1: Historical Context_《C++20Get the details》_notes
开发语言·c++20
独好紫罗兰26 分钟前
洛谷题单2-P5712 【深基3.例4】Apples-python-流程图重构
开发语言·python·算法
东方佑41 分钟前
深度解析Python-PPTX库:逐层解析PPT内容与实战技巧
开发语言·python·powerpoint
水w1 小时前
【Android Studio】如何卸载干净(详细步骤)
android·开发语言·android studio·activity
weixin_307779131 小时前
判断HiveQL语句为建表语句的识别函数
开发语言·数据仓库·hive·c#
一顿操作猛如虎,啥也不是!1 小时前
JAVA-Spring Boot多线程
开发语言·python
v维焓1 小时前
C++(思维导图更新)
开发语言·c++·算法
jiet_h1 小时前
深入解析KSP(Kotlin Symbol Processing):现代Android开发的新利器
android·开发语言·kotlin