最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

网站源码admin2浏览0评论

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

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


一、默认成员函数

1. 默认构造函数

  • 语法vector<T> vec;
  • 行为:创建空容器,容量为 0,不分配内存。
  • 示例: 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 的元素的容器。
  • 示例: 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
  • 示例: 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};
  • 行为:直接通过列表初始化元素。
  • 示例: std::vector<int> vec = {4, 5, 6}; // {4, 5, 6}

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

  • 语法: vector<T> vec2(vec1); // 拷贝构造 vec2 = vec1; // 赋值运算符
  • 行为:深拷贝容器内容,新旧容器完全独立。
  • 示例: 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代码运行次数:0运行复制
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)
  • 语法: 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代码运行次数:0运行复制
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代码运行次数:0运行复制
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代码运行次数:0运行复制
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() 返回迭代器。 std::vector<int> vec = {1, 2, 3}; vec.front() = 10; // 直接修改首元素 auto it = vec.begin(); *it = 20; // 通过迭代器修改

3. 底层数据指针 data()

  • 语法T* data();
  • 行为:返回指向底层数组的指针(C++11 起支持)。
  • 示例: 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代码运行次数:0运行复制
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 的多个重载版本
  • 语法: 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 指向的元素
  • 示例: 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 的用法
  • 语法: iterator erase(iterator pos); // 删除单个元素 iterator erase(iterator first, iterator last); // 删除范围元素
  • 示例: 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代码运行次数:0运行复制
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的底层原理和模拟实现

发布评论

评论列表(0)

  1. 暂无评论