【C++ STL】std::vector
第一章:std::vector 核心函数列表与详解
1. 构造与赋值函数
构造函数
- 函数功能:支持默认构造、填充构造(大小+初始值)、范围构造(迭代器)、拷贝构造、移动构造及初始化列表构造。
- 函数入参:依构造方式不同,可传入
size_type count,const T& value,InputIt first/last,const vector& other,vector&& other,initializer_list<T>等。 - 函数返回值:无(构造对象本身)
- 使用举例:
std::vector<int> v1; // 默认构造(空) std::vector<int> v2(5); // 填充构造(5个默认值) std::vector<int> v3(5, 42); // 填充构造(5个42) std::vector<int> v4(v3); // 拷贝构造 std::vector<int> v5(std::move(v4)); // 移动构造 int arr[] = {1, 2, 3}; std::vector<int> v6(arr, arr + 3); // 迭代器范围构造 std::vector<int> v7 = {10, 20, 30}; // 初始化列表构造
operator=
- 函数功能:替换容器内容。支持拷贝赋值、移动赋值和初始化列表赋值。
- 函数入参:
const vector& other/vector&& other/initializer_list<T> - 函数返回值:
vector&(指向自身的引用) - 使用举例:
std::vector<int> src = {1, 2, 3}; std::vector<int> dst; dst = src; // 拷贝赋值 dst = std::move(src); // 移动赋值 dst = {10, 20, 30}; // 初始化列表赋值
assign
- 函数功能:替换容器内容。支持填充赋值、迭代器范围赋值和初始化列表赋值。
- 函数入参:
size_type count, const T& value或InputIt first, last或initializer_list<T> - 函数返回值:无 (
void) - 使用举例:
std::vector<int> v; v.assign(4, 99); // 4个99: [99,99,99,99] int arr[] = {1, 2, 3}; v.assign(arr, arr + 3); // 从数组范围: [1,2,3] v.assign({10, 20, 30}); // 初始化列表: [10,20,30]
2. 元素访问函数
operator[]
- 函数功能:访问指定位置的元素,不进行边界检查,性能最高。
- 函数入参:
size_type pos(元素索引) - 函数返回值:
reference或const_reference - 使用举例:
std::vector<int> v = {10, 20, 30}; int x = v[0]; // 读取首元素:10 v[1] = 99; // 修改元素:[10,99,30]
at
- 函数功能:访问指定位置的元素,进行边界检查,越界时抛出
std::out_of_range异常。 - 函数入参:
size_type pos(元素索引) - 函数返回值:
reference或const_reference - 使用举例:
std::vector<int> v = {10, 20, 30}; try { int x = v.at(2); // 正常访问:30 v.at(100) = 0; // 越界,抛出异常 } catch (const std::out_of_range& e) { // 处理越界 }
front
- 函数功能:访问容器的第一个元素。
- 函数入参:无
- 函数返回值:
reference或const_reference - 使用举例:
std::vector<int> v = {10, 20, 30}; int first = v.front(); // 获取首元素:10 v.front() = 100; // 修改首元素:[100,20,30]
back
- 函数功能:访问容器的最后一个元素。
- 函数入参:无
- 函数返回值:
reference或const_reference - 使用举例:
std::vector<int> v = {10, 20, 30}; int last = v.back(); // 获取尾元素:30 v.back() = 300; // 修改尾元素:[10,20,300]
data
- 函数功能:返回指向底层连续内存数组的指针,常用于与 C 风格 API 交互。
- 函数入参:无
- 函数返回值:
T*或const T* - 使用举例:
std::vector<int> v = {10, 20, 30}; int* p = v.data(); // 获取裸指针 int second = *(p + 1); // 通过指针访问:20 // 可传入需要 C 风格数组的函数,如:memcpy(arr, v.data(), v.size()*sizeof(int))
3. 迭代器函数
begin / end
- 函数功能:返回指向首元素 / 尾后元素的普通迭代器。
- 函数入参:无
- 函数返回值:
iterator或const_iterator - 使用举例:
std::vector<int> v = {1, 2, 3}; for (auto it = v.begin(); it != v.end(); ++it) { std::cout << *it << " "; // 输出:1 2 3 }
cbegin / cend
- 函数功能:返回指向首元素 / 尾后元素的常量迭代器 (C++11)。
- 函数入参:无
- 函数返回值:
const_iterator - 使用举例:
const std::vector<int> v = {1, 2, 3}; for (auto it = v.cbegin(); it != v.cend(); ++it) { std::cout << *it << " "; // 只读遍历 }
rbegin / rend
- 函数功能:返回指向首元素 / 尾后元素的反向迭代器。
- 函数入参:无
- 函数返回值:
reverse_iterator或const_reverse_iterator - 使用举例:
std::vector<int> v = {1, 2, 3}; for (auto it = v.rbegin(); it != v.rend(); ++it) { std::cout << *it << " "; // 逆序输出:3 2 1 }
crbegin / crend
- 函数功能:返回指向首元素 / 尾后元素的常量反向迭代器 (C++11)。
- 函数入参:无
- 函数返回值:
const_reverse_iterator - 使用举例:
const std::vector<int> v = {1, 2, 3}; for (auto it = v.crbegin(); it != v.crend(); ++it) { std::cout << *it << " "; // 只读逆序:3 2 1 }
4. 容量管理函数
empty
- 函数功能:检查容器是否为空。
- 函数入参:无
- 函数返回值:
bool - 使用举例:
std::vector<int> v; if (v.empty()) { // true // 容器为空时的处理 }
size
- 函数功能:返回容器中当前元素的个数。
- 函数入参:无
- 函数返回值:
size_type - 使用举例:
std::vector<int> v = {1, 2, 3, 4}; std::size_t n = v.size(); // n = 4
max_size
- 函数功能:返回容器支持的最大元素数量(理论极限)。
- 函数入参:无
- 函数返回值:
size_type - 使用举例:
std::vector<int> v; std::size_t max = v.max_size(); // 理论最大元素数
capacity
- 函数功能:返回当前已分配的底层内存空间可容纳的元素数量。
- 函数入参:无
- 函数返回值:
size_type - 使用举例:
std::vector<int> v; v.reserve(100); std::size_t cap = v.capacity(); // cap >= 100
reserve
- 函数功能:预分配内存,增加
capacity,不改变size,避免频繁扩容。 - 函数入参:
size_type new_cap(新的容量需求) - 函数返回值:无 (
void) - 使用举例:
std::vector<int> v; v.reserve(1000); // 预先分配1000个元素的空间 for (int i = 0; i < 1000; ++i) { v.push_back(i); // 不再触发多次扩容 }
resize
- 函数功能:改变容器中元素的个数 (
size)。若增加则值初始化或填充,若减少则截断。 - 函数入参:
size_type count, 可选const T& value(填充值) - 函数返回值:无 (
void) - 使用举例:
std::vector<int> v = {1, 2, 3}; v.resize(5); // 变大:[1,2,3,0,0] v.resize(10, 99); // 变大:[1,2,3,0,0,99,99,99,99,99] v.resize(2); // 变小:[1,2]
shrink_to_fit
- 函数功能:请求移除未使用的容量,使
capacity尽量贴近size(C++11,请求性操作)。 - 函数入参:无
- 函数返回值:无 (
void) - 使用举例:
std::vector<int> v; v.reserve(100); v.push_back(1); v.shrink_to_fit(); // 请求释放多余容量
5. 修改操作函数
clear
- 函数功能:清空所有元素,
size变为 0,但capacity保持不变。 - 函数入参:无
- 函数返回值:无 (
void) - 使用举例:
std::vector<int> v = {1, 2, 3}; v.clear(); // 清空元素,size=0, capacity不变
insert
- 函数功能:在指定迭代器位置前插入元素。支持单个、多个相同元素、迭代器范围及初始化列表。
- 函数入参:
iterator pos, 以及const T& value/count/first, last/initializer_list - 函数返回值:指向首个插入元素的
iterator - 使用举例:
std::vector<int> v = {1, 2, 3}; v.insert(v.begin(), 0); // 首前插入:[0,1,2,3] v.insert(v.end(), 3, 9); // 末尾插入3个9 int arr[] = {10, 20}; v.insert(v.begin(), arr, arr + 2); // 插入范围 v.insert(v.begin(), {100, 200}); // 初始化列表插入
emplace
- 函数功能:在指定位置原位构造元素,避免临时对象的拷贝/移动开销 (C++11)。
- 函数入参:
iterator pos,Args&&... args(构造参数) - 函数返回值:指向新构造元素的
iterator - 使用举例:
std::vector<std::pair<int,int>> v; v.emplace(v.begin(), 1, 2); // 原位构造 pair(1,2)
erase
- 函数功能:移除指定位置或范围内的元素,导致被删位置及之后的迭代器失效。
- 函数入参:
iterator pos或iterator first, last - 函数返回值:指向被删元素后一个元素的
iterator - 使用举例:
std::vector<int> v = {1, 2, 3, 4, 5}; v.erase(v.begin()); // 删除首元素:[2,3,4,5] v.erase(v.begin(), v.begin() + 2); // 删除范围:[4,5]
push_back
- 函数功能:在容器尾部添加元素(拷贝或移动)。
- 函数入参:
const T& value或T&& value - 函数返回值:无 (
void) - 使用举例:
std::vector<int> v; v.push_back(1); // 尾部加1 v.push_back(2); // 尾部加2 → [1,2]
emplace_back
- 函数功能:在容器尾部原位构造元素,避免临时对象开销 (C++11)。
- 函数入参:
Args&&... args(构造参数) - 函数返回值:
reference(C++17起返回引用) - 使用举例:
std::vector<std::string> v; v.emplace_back("hello"); // 原位构造 string v.emplace_back(5, 'a'); // 原位构造 "aaaaa"
pop_back
- 函数功能:移除容器的最后一个元素。
- 函数入参:无
- 函数返回值:无 (
void) - 使用举例:
std::vector<int> v = {1, 2, 3}; v.pop_back(); // 移除末尾 → [1,2]
swap
- 函数功能:交换两个容器的内容,时间复杂度 O(1),仅交换内部指针。
- 函数入参:
vector& other - 函数返回值:无 (
void) - 使用举例:
std::vector<int> a = {1, 2}, b = {3, 4}; a.swap(b); // a=[3,4], b=[1,2]
6. 非成员函数与特有函数
比较运算符
- 函数功能:按字典序逐元素比较两个 vector (
==,!=,<,<=,>,>=)。 - 函数入参:
const vector& lhs,const vector& rhs - 函数返回值:
bool - 使用举例:
std::vector<int> a = {1, 2, 3}; std::vector<int> b = {1, 2, 4}; bool eq = (a == b); // false bool lt = (a < b); // true(逐元素比较)
std::swap
- 函数功能:非成员版本的交换函数,通过 ADL 机制优先调用成员
swap。 - 函数入参:
vector& lhs,vector& rhs - 函数返回值:无 (
void) - 使用举例:
std::vector<int> a = {1, 2}, b = {3, 4}; std::swap(a, b); // 调用 ADL 的 swap
flip
- 函数功能:
vector<bool>特有:将所有位(元素)取反。 - 函数入参:无
- 函数返回值:无 (
void) - 使用举例:
std::vector<bool> vb = {true, false, true}; vb.flip(); // 变为 [false, true, false]
第二章:分模块代码示例
2.1 构造函数与赋值
包含默认构造、带参构造、拷贝/移动构造、迭代器范围构造、初始化列表构造,以及 assign 赋值和基于 new / 智能指针的堆内存动态创建。
void demo_constructors()
{
std::cout << "\n====== 1. 构造函数与赋值 ======\n";
std::vector<int> v1; // 默认构造
std::vector<int> v2(5); // 填充构造
std::vector<int> v3(5, 42); // 填充构造带初始值
std::vector<int> v4(v3); // 拷贝构造
std::vector<int> v5(std::move(v4)); // 移动构造
int arr[] = { 10, 20, 30 };
std::vector<int> v6(std::begin(arr), std::end(arr)); // 迭代器范围构造
std::vector<int> v7 = { 1, 2, 3 }; // 初始化列表构造
v1 = v7; // 拷贝赋值
v2 = std::move(v1); // 移动赋值
v3 = { 100, 200 }; // 初始化列表赋值
v4.assign(4, 999); // assign 批量赋值
// new 动态创建与智能指针管理
auto upv = std::make_unique<std::vector<int>>(std::initializer_list<int>{1, 2, 3});
upv->push_back(4);
}
2.2 元素访问
演示 operator[](无边界检查)、at()(带边界检查及异常捕获)、front()/back()(首尾访问)以及 data()(获取底层数组指针)。
void demo_element_access()
{
std::vector<int> vec = { 10, 20, 30, 40, 50 };
vec[2] = 300; // 下标访问
try { vec.at(100); } // 越界异常捕获
catch (const std::out_of_range& e) { /* ... */ }
vec.front() = 1000; // 修改首元素
vec.back() = 5000; // 修改尾元素
int* p = vec.data(); // 获取底层指针
}
2.3 迭代器
演示正向、反向、常量迭代器的使用,以及 C++11 范围 for 循环的底层逻辑。
void demo_iterators()
{
std::vector<int> vec = { 1, 2, 3, 4, 5 };
for (auto it = vec.begin(); it != vec.end(); it++) { /* 正向迭代 */ }
for (auto it = vec.cbegin(); it != vec.cend(); it++) { /* const 迭代 */ }
for (auto it = vec.rbegin(); it != vec.rend(); it++) { /* 反向迭代 */ }
for (int x : vec) { /* 范围 for 循环 */ }
}
2.4 容量操作
演示 empty、size、capacity、max_size 的查询,以及 reserve(预分配内存)、resize(改变元素个数)和 shrink_to_fit(释放多余容量)的使用。
void demo_capacity()
{
std::vector<int> vec;
vec.reserve(20); // 预分配内存,只改 capacity
for (int i = 0; i < 10; i++) vec.push_back(i);
vec.resize(15); // 改变元素个数,新增元素值初始化
vec.resize(20, 99); // 新增元素用 99 填充
vec.resize(5); // 截断尾部元素
vec.shrink_to_fit(); // 请求释放多余容量
}
2.5 修改操作
演示尾部插入/删除 (push_back, emplace_back, pop_back),指定位置插入/原位构造/删除 (insert, emplace, erase),以及 clear 和 swap(包含利用 swap 释放内存的经典技巧)。
void demo_modifiers()
{
std::vector<int> vec;
vec.push_back(1);
vec.pop_back();
auto it = vec.begin();
vec.insert(it, 100); // 指定位置插入
vec.erase(vec.begin() + 1); // 指定位置删除
vec.clear(); // 清空元素,capacity 不变
std::vector<int> huge(10000);
huge.clear();
std::vector<int>().swap(huge); // 利用 swap 强制释放内存
}
2.6 与 STL 算法配合
演示 vector 与 <algorithm> 及 <numeric> 库中算法的结合,包括排序、查找、计数、遍历、变换、累加、去重、二分查找及 C++20 的 std::erase。
void demo_algorithms()
{
std::vector<int> vec = { 5, 2, 8, 1, 9 };
std::sort(vec.begin(), vec.end()); // 排序
auto it = std::find(vec.begin(), vec.end(), 7); // 查找
int sum = std::accumulate(vec.begin(), vec.end(), 0); // 累加
// 删除-擦除惯用法 (Erase-Remove Idiom)
vec.erase(std::remove_if(vec.begin(), vec.end(), [](int x) {return x % 2 == 0; }), vec.end());
}
2.7 非成员函数与比较
演示 vector 的字典序比较运算符及非成员 std::swap。
void demo_non_member()
{
std::vector<int> a = { 1, 2, 3 };
std::vector<int> b = { 1, 2, 4 };
bool is_less = (a < b); // 字典序比较
std::swap(a, b); // 非成员 swap
}
2.8 二维 vector
演示二维 vector 的多种创建方式:规则矩阵初始化、初始化列表构造、不规则锯齿数组(逐行 push_back),以及性能最优的 reserve + emplace_back 组合。
void demo_2d_vector()
{
// M 行 N 列,初始值为 0
std::vector<std::vector<int>> matrix(3, std::vector<int>(4, 0));
// 初始化列表
std::vector<std::vector<int>> mat2 = { {1, 2}, {3, 4} };
// 锯齿数组
std::vector<std::vector<int>> jagged;
jagged.push_back({ 1 });
jagged.push_back({ 2, 3 });
}
2.9 三维 vector
演示三维 vector(D层 × M行 × N列)的嵌套构造、初始化列表构造及逐层 reserve 构建方式。
void demo_3d_vector()
{
// D层 × M行 × N列
std::vector<std::vector<std::vector<int>>> tensor(
2, std::vector<std::vector<int>>(3, std::vector<int>(4, 0))
);
// 初始化列表
std::vector<std::vector<std::vector<int>>> tensor2 = {
{ {1, 2}, {3, 4} },
{ {5, 6}, {7, 8} }
};
}
2.10 工程化最佳实践
总结传参规范、reserve 预分配、emplace_back 优化、范围 for 引用修改、迭代器失效的安全循环 erase 写法等工程经验。
void demo_best_practices()
{
std::vector<int> nums = { 1, 2, 3, 4, 5, 6 };
// 安全循环 erase
for (auto it = nums.begin(); it != nums.end(); )
{
if (*it % 2 == 0) it = nums.erase(it); // 使用返回值更新迭代器
else it++;
}
}
2.11 vector 优化
演示 std::vector<bool> 的特化行为(位压缩存储)及其特有的 flip() 函数,并说明代理引用(Proxy Reference)的潜在陷阱。
void demo_vector_bool()
{
std::vector<bool> vb = { true, false, true };
vb.flip(); // 全体取反
}
第三章:完整代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <stdexcept>
#include <cassert>
#include <initializer_list>
#include <memory>
/*
* std::vector 全用法工程化示例
* 涵盖:构造/访问/迭代器/容量/修改/算法/非成员函数/异常安全
*/
/**
* @brief
* 打印 vector 内容(工程化调试工具函数)
* @tparam T
* @param vec
* @param label
*/
template <typename T>
void print_vector(const std::vector<T>& vec, const std::string& label = "")
{
if (!label.empty())
{
std::cout << label << ": ";
}
std::cout << "[size=" << vec.size()
<< ", capacity=" << vec.capacity() << "] ";
for (size_t i = 0; i < vec.size(); ++i)
{
if (i > 0) std::cout << ", ";
std::cout << vec[i];
}
std::cout << "\n";
}
/**
* @brief 自定义类型,用于演示 emplace / 移动语义
*/
class Widget
{
private:
int m_id;
std::string m_name;
public:
// 默认构造
Widget() : m_id(0) {}
// 带参构造
explicit Widget(int id, std::string name = "")
: m_id(id), m_name(std::move(name))
{
}
// 拷贝构造
Widget(const Widget& other) = default;
// 移动构造
Widget(Widget&& other) noexcept
: m_id(other.m_id), m_name(std::move(other.m_name))
{
other.m_id = 0;
}
// 拷贝赋值
Widget& operator=(const Widget& other) = default;
// 移动赋值
Widget& operator=(Widget&& other) noexcept
{
if (this != &other)
{
m_id = other.m_id;
m_name = std::move(other.m_name);
other.m_id = 0;
}
return *this;
}
int id() const
{
return m_id;
}
const std::string& name() const
{
return m_name;
}
bool operator<(const Widget& rhs) const
{
return m_id < rhs.m_id;
}
bool operator==(const Widget& rhs) const
{
return m_id == rhs.m_id;
}
};
std::ostream& operator<<(std::ostream& os, const Widget& w)
{
os << "Widget{id=" << w.id() << ", name='" << w.name() << "'}";
return os;
}
// ============================================================
/**
* @brief 构造函数与赋值
*/
void demo_constructors()
{
std::cout << "\n====== 1. 构造函数与赋值 ======\n";
/* 1.1 默认构造:空 vector */
std::vector<int> v1;
print_vector(v1, "默认构造 v1");
/* 1.2 带初始大小的构造(值初始化,int为0) */
std::vector<int> v2(5);
print_vector(v2, "指定大小 v2(5)");
/* 1.3 指定大小 + 初始值 */
std::vector<int> v3(5, 42);
print_vector(v3, "指定大小 v3(5)");
/* 1.4 拷贝构造 */
std::vector<int> v4(v3);
print_vector(v4, "拷贝构造 v4(v3)");
/* 1.5 移动构造(C++ 11) */
std::vector<int> v5(std::move(v4));
print_vector(v5, "移动构造 v5(std::move(v4))");
print_vector(v4, "移动后 v4 状态");
/* 1.6 迭代器范围构造 */
int arr[] = { 10, 20, 30, 40, 50 };
std::vector<int> v6(std::begin(arr), std::end(arr));
print_vector(v6, "迭代器范围 v6");
/* 1.7 初始化列表构造(C++ 11) */
std::vector<int> v7 = { 1, 2, 3, 4, 5 };
std::vector<int> v8{ 11, 22, 33 };
print_vector(v7, "初始化列表 v7");
print_vector(v8, "初始化列表 v8");
/* 1.8 拷贝赋值 */
v1 = v7;
print_vector(v1, "拷贝赋值 v1 = v7");
/* 1.9 移动赋值 */
v2 = std::move(v1);
print_vector(v2, "移动赋值 v2 = std::move(v1)");
/* 1.10 initializer_list 赋值 */
v3 = { 100, 200, 300 };
print_vector(v3, "初始化列表赋值 v3 = {...}");
/* 1.11 assign: 批量赋值(大小+值) */
v4.assign(4, 999);
print_vector(v4, "assign(4, 999)");
/* 1.12 assign: 迭代器范围 */
v5.assign(v8.begin(), v8.end());
print_vector(v5, "assign(迭代器范围)");
/* 1.13 assign: 初始化列表 */
v6.assign({ 7, 8, 9 });
print_vector(v6, "assign(初始化列表)");
/* 1.14 new 动态创建 vector (堆分配) */
{
std::cout << "\n--- new 动态创建 ---\n";
// 默认构造
std::vector<int>* pv1 = new std::vector<int>();
pv1->push_back(10);
pv1->push_back(20);
pv1->push_back(30);
print_vector(*pv1, "new 默认构造 pv1");
// 带参构造:指定大小 + 初始值
std::vector<int>* pv2 = new std::vector<int>(5, 88);
print_vector(*pv2, "new 指定大小 pv2(5, 88)");
// 初始化列表构造
std::vector<int>* pv3 = new std::vector<int>{ 100, 200, 300, 400 };
print_vector(*pv3, "new 初始化列表 pv3");
// 拷贝构造(从已有 vector 拷贝)
std::vector<int>* pv4 = new std::vector<int>(*pv3);
print_vector(*pv4, "new 拷贝构造 pv4(*pv3)");
// 使用完毕后必须 delete 释放内存
delete pv1;
delete pv2;
delete pv3;
delete pv4;
/*
* 裸 new 需要手动 delete,极易泄漏,不推荐
* 优先使用智能指针 std::unique_ptr / std::shared_ptr 管理堆上 vector
*/
std::cout << "\n--- 智能指针管理堆 vector ---\n";
// std::unique_ptr 管理(自动释放,零开销)
auto upv = std::make_unique<std::vector<int>>(std::initializer_list<int>{1, 2, 3});
upv->push_back(4);
print_vector(*upv, "unique_ptr vector");
// std::shared_ptr 管理(引用计数,可共享)
auto spv = std::make_shared<std::vector<int>>(4, 77);
print_vector(*spv, "shared_ptr vector");
// 离开作用域自动释放,无需手动 delete
}
}
// ============================================================
/**
* @brief 元素访问
*/
void demo_element_access()
{
std::cout << "\n====== 2. 元素访问 ======\n";
std::vector<int> vec = { 10, 20, 30, 40, 50 };
print_vector(vec, "原始 vec");
/* 2.1 operator[]: 下标访问,不做边界检查 */
std::cout << "vec[2] = " << vec[2] << "\n";
vec[2] = 300;
std::cout << "修改后 vec[2] = " << vec[2] << "\n";
/* 2.2 at(): 带边界检查,越界抛出 std::out_of_range */
try
{
std::cout << "vec.at(3) = " << vec.at(3) << "\n";
std::cout << "vec.at(100) = 越界访问\n";
vec.at(100); // 触发异常
}
catch (const std::out_of_range& e)
{
// invalid vector subscript
std::cout << "捕获越界异常: " << e.what() << "\n";
}
/* 2.3 front() / back(): 首尾元素引用 */
std::cout << "front() = " << vec.front() << "\n";
std::cout << "back() = " << vec.back() << "\n";
vec.front() = 1000;
vec.back() = 5000;
print_vector(vec, "修改首尾后");
/* 2.4 data(): 返回底层数组指针(C++ 11) */
int* p = vec.data();
std::cout << "data()[0] = " << p[0] << "\n";
// 可直接用于 C 风格接口
}
// ============================================================
/**
* @brief 迭代器
*/
void demo_iterators()
{
std::cout << "\n====== 3. 迭代器 ======\n";
std::vector<int> vec = { 1, 2, 3, 4, 5 };
/* 3.1 普通迭代器 begin/end */
std::cout << "正向迭代: ";
for (auto it = vec.begin(); it != vec.end(); it++)
{
std::cout << *it << " ";
}
std::cout << "\n";
/* 3.2 const 迭代器 cbegin/cend (C++ 11) */
std::cout << "const 迭代: ";
for (auto it = vec.cbegin(); it != vec.cend(); it++)
{
std::cout << *it << " ";
}
std::cout << "\n";
/* 3.3 反向迭代器 rbegin/rend */
std::cout << "反向迭代: ";
for (auto it = vec.rbegin(); it != vec.rend(); it++)
{
std::cout << *it << " ";
}
std::cout << "\n";
/* 3.4 const 反向迭代器 crbegin/crend (C++ 11) */
std::cout << "const 反向: ";
for (auto it = vec.crbegin(); it != vec.crend(); it++)
{
std::cout << *it << " ";
}
std::cout << "\n";
/* 3.5 范围 for 循环(底层基于迭代器) */
std::cout << "范围 for: ";
for (int x : vec)
{
std::cout << x << " ";
}
std::cout << "\n";
/*
* 3.6 迭代器失效说明:
* - insert / push_bash 可能导致所有迭代器失效(重新分配内存时)
* - erase 导致被删位置及之后的迭代器失效
* - 仅在尾部插入/删除且不扩容时,尾前迭代器可能保持有效
*/
}
// ============================================================
/**
* @brief 容量操作
*/
void demo_capacity()
{
std::cout << "\n====== 4. 容量操作 ======\n";
std::vector<int> vec;
std::cout << "初始空 vector\n";
std::cout << " empty() = " << std::boolalpha << vec.empty() << "\n";
std::cout << " size() = " << vec.size() << "\n";
std::cout << " capacity() = " << vec.capacity() << "\n";
std::cout << " max_size() = " << vec.max_size() << "\n";
/* 4.1 reserve: 预分配内存,只改capacity,不改size */
vec.reserve(20);
std::cout << "\nreserve(20) 后:\n";
std::cout << " size() = " << vec.size() << "\n";
std::cout << " capacity() = " << vec.capacity() << "\n";
/* 4.2 push_back 不扩容时迭代器有效 */
for (int i = 0; i < 10; i++)
{
vec.push_back(i);
}
print_vector(vec, "push_back 10 个元素");
/* 4.3 resize: 改变元素个数 */
vec.resize(15); // 新增元素值初始化
print_vector(vec, "resize(15) 后");
vec.resize(20, 99); // 新增元素用99填充
print_vector(vec, "resize(20, 99) 后");
vec.resize(5); // 截断尾部元素
print_vector(vec, "resize(5) 截断后");
/* 4.4 shrink_to_fit: 释放多于容量(C++ 11,请求性,不保证) */
vec.shrink_to_fit();
std::cout << "shrink_to_fit 后 capacity = " << vec.capacity() << "\n";
/* 4.5 工程化最佳实践:已知大小时优先 reserve 避免多次扩容 */
std::vector<int> big_vec;
big_vec.reserve(1000); // 一次性分配,避免多次 realloc
for (int i = 0; i < 1000; i++)
{
big_vec.push_back(i);
}
std::cout << "预分配 1000 后:size=" << big_vec.size()
<< ", capacity=" << big_vec.capacity() << "\n";
}
// ============================================================
/**
* @brief 修改操作
*/
void demo_modifiers()
{
std::cout << "\n====== 5. 修改操作 ======\n";
/* 5.1 push_back: 尾部插入(拷贝) */
std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
print_vector(vec, "push_back 三次");
/* 5.2 emplace_back: 尾部原位构造(C++ 11,避免临时对象) */
std::vector<Widget> widgets;
widgets.emplace_back(1, "A");
widgets.emplace_back(2, "B");
std::cout << "emplac_back 两个 Widget, size=" << widgets.size() << "\n";
/* 5.3 pop_back: 尾部删除(不返回值) */
vec.pop_back();
print_vector(vec, "pop_back 后");
/* 5.4 insert: 指定位置插入 */
auto it = vec.begin() + 1;
vec.insert(it, 100); // 单个元素
print_vector(vec, "insert 单个 100");
it = vec.begin();
vec.insert(it, 3, 50); // n 个相同元素
print_vector(vec, "insert 3 个 50");
int arr[] = { 7, 8, 9 };
vec.insert(vec.end(), std::begin(arr), std::end(arr)); // 迭代器范围
print_vector(vec, "insert 数组范围");
vec.insert(vec.begin(), { 101, 102 }); // 初始化列表
print_vector(vec, "insert 初始化列表");
/* 5.5 emplace: 指定位置原位构造(C++ 11) */
std::vector<Widget> wvec;
wvec.emplace_back(10, "X");
wvec.emplace(wvec.begin(), 20, "Y");
print_vector(wvec, "wvec");
std::cout << "emplace 后 Widget 数量: " << wvec.size() << "\n";
/* 5.6 erase: 删除指定位置元素 */
auto v_it = vec.begin() + 2;
vec.erase(v_it);
print_vector(vec, "erase 第 3 个元素");
/* 5.7 erase: 范围删除 [first, last) */
vec.erase(vec.begin() + 1, vec.begin() + 4);
print_vector(vec, "erase 范围 [1,4)");
/* 5.8 clear: 清空所有元素,capacity不变 */
vec.clear();
std::cout << "clear 后: size=" << vec.size()
<< ", capacity=" << vec.capacity() << "\n";
/* 5.9 swap: 交换两个 vector 内容(O(1),只交换内部指针) */
std::vector<int> a = { 1, 2, 3 };
std::vector<int> b = { 10, 20, 30, 40, 50 };
print_vector(a, "交换前 a");
print_vector(b, "交换前 b");
a.swap(b);
print_vector(a, "交换前 a");
print_vector(b, "交换前 b");
/* 5.10 利用 swap 前置释放内存(经典技巧) */
std::vector<int> huge(10000);
std::cout << "huge 容量: " << huge.capacity() << "\n";
huge.clear();
std::cout << "clear 后容量: " << huge.capacity() << "\n";
std::vector<int>().swap(huge); // 临时空 vector 交换
std::cout << "swap 释放后容量: " << huge.capacity() << "\n";
}
// ============================================================
/**
* @brief 与 STL 算法配合
*/
void demo_algorithms()
{
std::cout << "\n====== 6. STL 算法配合 ======\n";
std::vector<int> vec = { 5, 2, 8, 1, 9, 3, 7, 4, 6 };
print_vector(vec, "原始 vec");
/* 6.1 sort: 排序 */
std::sort(vec.begin(), vec.end());
print_vector(vec, "sort 升序");
std::sort(vec.rbegin(), vec.rend());
print_vector(vec, "sort 降序");
/* 6.2 find: 查找元素 */
auto it = std::find(vec.begin(), vec.end(), 7);
if (it != vec.end())
{
std::cout << "找到 7,下标: " << std::distance(vec.begin(), it) << "\n";
}
/* 6.3 find_if: 条件查找 */
it = std::find_if(vec.begin(), vec.end(), [](int x) { return x < 3; });
if (it != vec.end())
{
std::cout << "找到第一个小于 3 的数: " << *it << "\n";
}
/* 6.4 count / count_if: 计数 */
int cnt = std::count(vec.begin(), vec.end(), 5);
std::cout << "5 出现次数: " << cnt << "\n";
int even_cnt = std::count_if(vec.begin(), vec.end(),
[](int x) { return x % 2 == 0; });
std::cout << "偶数个数: " << even_cnt << "\n";
/* 6.5 for_each: 遍历 */
std::cout << "for_each 输出: ";
std::for_each(vec.begin(), vec.end(), [](int& x) {std::cout << x << " "; });
std::cout << "\n";
/* 6.6 transform: 变换 */
std::vector<int> out;
out.reserve(vec.size());
std::transform(vec.begin(), vec.end(), std::back_inserter(out), [](int x) {return x * 2; });
print_vector(out, "transform 乘 2");
/* 6.7 accumulate: 累加(numeric) */
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::cout << "累加和: " << sum << "\n";
/* 6.8 unique + erase: 去重经典写法 */
std::vector<int> dup = { 1, 2, 3, 3, 3, 4, 5, 5 };
std::sort(dup.begin(), dup.end());
auto last = std::unique(dup.begin(), dup.end());
dup.erase(last, dup.end());
print_vector(dup, "去重后");
/* 6.9 lower_bound / upper_bound (需有序) */
std::sort(vec.begin(), vec.end());
auto lb = std::lower_bound(vec.begin(), vec.end(), 5);
std::cout << "lower_bound(5) 指向: " << *lb << "\n";
/* 6.10 reverse: 反转 */
std::reverse(vec.begin(), vec.end());
print_vector(vec, "reverse 后");
/* 6.11 remove / remove_if + erase: 删除-擦除惯用法 */
std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// 删除所有偶数
nums.erase(std::remove_if(nums.begin(), nums.end(), [](int x) {return x % 2 == 0; }),
nums.end());
print_vector(nums, "删除所有偶数后");
/* 6.12 std::erase / std::erase_if (C++ 20,成员级别的便捷函数) */
#if __cplusplus >= 202002L
std::vector<int> v20 = { 1, 2, 3, 2, 4, 2, 5 };
std::erase(v20, 2); // 删除所有值为2的元素
print_vector(v20, "C++ 20 std::erase(2)");
std::erase_if(v20, [](int x) { return x > 3; });
print_vector(v20, "C++ 20 std::erase_if(>3)");
#endif
}
// ============================================================
/**
* @brief 非成员函数与比较
*/
void demo_non_member()
{
std::cout << "\n====== 7. 非成员函数与比较 ======\n";
std::vector<int> a = { 1, 2, 3 };
std::vector<int> b = { 1, 2, 3 };
std::vector<int> c = { 1, 2, 4 };
/* 7.1 比较运算符(按字典序逐元素比较) */
std::cout << std::boolalpha;
std::cout << "a == b : " << (a == b) << "\n";
std::cout << "a != c : " << (a != c) << "\n";
std::cout << "a < c : " << (a < c) << "\n";
std::cout << "a <= b : " << (a <= b) << "\n";
std::cout << "c > a : " << (c > a) << "\n";
std::cout << "c >= b : " << (c >= b) << "\n";
/* 7.2 std::swap 非成员版本(ADL 优先调用成员 swap) */
std::swap(a, c);
print_vector(a, "std::swap 后 a");
print_vector(c, "std::swap 后 c");
}
// ============================================================
/**
* @brief 二维 vector 与嵌套
*/
void demo_2d_vector()
{
std::cout << "\n====== 8. 二维 vector ======\n";
/* 8.1 初始化 M×N 的二维数组 */
int rows = 3, cols = 4;
std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols, 0));
/* 8.2 赋值 */
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
matrix[i][j] = i * cols + j;
}
}
/* 8.3 遍历 */
std::cout << "3×4 矩阵: \n";
for (const auto& row : matrix)
{
for (int val : row)
{
std::cout << val << "\t";
}
std::cout << "\n";
}
/* 8.4 初始化列表构造二维 */
std::vector<std::vector<int>> mat2 = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
std::cout << "初始化列表二维矩阵:\n";
for (const auto& row : mat2)
{
for (int v : row)
{
std::cout << v << " ";
}
std::cout << "\n";
}
/* 8.5 逐行动态 push_back(不规则矩阵 / 锯齿数组) */
std::vector<std::vector<int>> jagged;
jagged.push_back({ 1 });
jagged.push_back({ 2, 3 });
jagged.push_back({ 4, 5, 6 });
jagged.push_back({ 7, 8, 9, 10 });
std::cout << "\njagged (锯齿数组,每行长度不同):\n";
for (size_t i = 0; i < jagged.size(); ++i)
{
std::cout << " row[" << i << "] (size=" << jagged[i].size() << "):";
for (int v : jagged[i]) std::cout << v << " ";
std::cout << "\n";
}
/* 8.6 先 reserve 行数,再逐行 emplace_back(性能最优) */
std::vector<std::vector<int>> mat4;
mat4.reserve(3); // 预分配行容量
for (int i = 0; i < 3; i++)
{
std::vector<int> row(4, i * 10); // 每行 4 列
mat4.emplace_back(std::move(row)); // 移动语义,避免拷贝
}
std::cout << "\nmat4 (reserve + emplace_back):\n";
for (const auto& row : mat4)
{
for (int v : row) std::cout << v << "\t";
std::cout << "\n";
}
/*
* 注意:二维 vector 每行内存独立分配,行与行之间不连续
* 如需连续内存的二维数组,可用一维 vector 模拟:
* std::vector<int> flat(rows * cols);
* flat[i * cols + j] = value;
*/
}
// ============================================================
/**
* @brief 三维 vector 创建
*/
void demo_3d_vector()
{
std::cout << "\n====== 9. 三维 vector ======\n";
/* 9.1 D层 × M行 × N列,初始值为0 */
int depth = 2, rows = 3, cols = 4;
std::vector<std::vector<std::vector<int>>> tensor(
depth,
std::vector<std::vector<int>>(
rows,
std::vector<int>(cols, 0)
)
);
// 填充数据:tensor[d][r][c] = d * 100 + r * 10 + c
for (int d = 0; d < depth; d++)
{
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
tensor[d][r][c] = d * 100 + r * 10 + c;
}
}
}
std::cout << "tensor (" << depth << "x" << rows << "x" << cols << "):\n";
for (int d = 0; d < depth; d++)
{
std::cout << " layer[" << d << "]:\n";
for (int r = 0; r < rows; r++)
{
std::cout << " ";
for (int c = 0; c < cols; c++)
{
std::cout << tensor[d][r][c] << "\t";
}
std::cout << "\n";
}
}
/* 9.2 初始化列表直接构造 */
std::vector<std::vector<std::vector<int>>> tensor2 = {
{
{1, 2},
{3, 4}
},
{
{5, 6},
{7, 8}
}
};
std::cout << "\ntensor2 (初始化列表 2×2×2):\n";
for (size_t d = 0; d < tensor2.size(); d++)
{
std::cout << " layer[" << d << "]:\n";
for (const auto& row : tensor2[d])
{
std::cout << " ";
for (int v : row) std::cout << v << " ";
std::cout << "\n";
}
}
/* 9.3 逐层逐行构建(适用于运行时确定维度的场景) */
std::vector<std::vector<std::vector<int>>> tensor3;
tensor3.reserve(2); // 预分配层数
for (int d = 0; d < 2; d++)
{
std::vector<std::vector<int>> layer;
layer.reserve(3);
for (int r = 0; r < 3; r++)
{
std::vector<int> row(2, d * 10 + r);
layer.emplace_back(std::move(row));
}
tensor3.emplace_back(std::move(layer));
}
std::cout << "\ntensor3 (逐层 reserve + emplace_back):\n";
for (size_t d = 0; d < tensor3.size(); d++)
{
std::cout << " layer[" << d << "]:\n";
for (const auto& row : tensor3[d])
{
std::cout << " ";
for (int v : row) std::cout << v << " ";
std::cout << "\n";
}
}
/*
* 建议:
* - 三维及以上 vector 嵌套层次深,可读性差,内存碎片多
* - 推荐封装为一维 vector + 多维索引计算:
* std::vector<int> flat(depth * rows * cols);
* flat[(d * rows + r) * cols + c] = value;
* - 或使用第三方库(如 Eigen、xtensor)处理多维数组
*/
}
// ============================================================
/**
* @brief 工程化注意事项与最佳实践
*/
void demo_best_practices()
{
std::cout << "\n====== 10. 工程化最佳实践 ======\n";
/*
* 10.1 传参规范
* - 只读: const std::vector<T>&
* - 写入: std::vector<T>&
* - 转移所有权: std::vector<T>&& 或直接传值
*/
/* 10.2 reserve 预分配,避免多次扩容(性能敏感场景) */
std::vector<int> v;
v.reserve(100);
for (int i = 0; i < 100; i++)
{
v.push_back(i);
}
std::cout << "reserve 后 100 元素: capacity=" << v.capacity() << "\n";
/* 10.3 自定义类型优先 emplace_back 而非 push_back(临时对象) */
std::vector<Widget> wv;
wv.reserve(10);
wv.emplace_back(1, "hello"); // 直接构造,零拷贝
//wv.push_back(Widget(1, "hello")); // 构造 + 移动/拷贝
/* 10.4 range-based for 中修改元素用引用 */
for (auto& x : v)
{
x *= 2;
}
/* 10.5 只读遍历用 const 引用 */
for (const auto& x : v)
{
(void)x; // 使用 x
}
/*
* 10.6 迭代器失效场景注意
* - 循环中 erase 必须使用返回值更新迭代器
*/
std::vector<int> nums = { 1, 2, 3, 4, 5, 6 };
for (auto it = nums.begin(); it != nums.end(); /* no increment */)
{
if (*it % 2 == 0)
{
it = nums.erase(it); // erase 返回下一个有效迭代器
}
else
{
it++;
}
}
print_vector(nums, "安全循环 erase 后");
/* 10.7 at() 用于边界不确定场景,operator[] 用于性能关键且边界有保障场景 */
/* 10.8 shrink_to_fit 仅在内存紧张、vector长期存活且后续不再增长时使用 */
v.shrink_to_fit();
std::cout << "工程化要点演示完成\n";
}
// ============================================================
/**
* @brief bool 特化 (std::vector<bool> 空间优化的位压缩)
*/
void demo_vector_bool()
{
std::cout << "\n====== 11. vector<bool> 优化 ======\n";
std::vector<bool> vb = { true, false, true, true, false };
std::cout << "vector<bool> size = " << vb.size() << "\n";
/*
* 注意:sizeof 每个元素不到 1 字节,位存储
* operator[] 返回代理对象 (proxy reference),不是 bool&
* 常见坑:不能取地址、auto 推导可能出问题
*/
vb.flip(); // 全体取反
std::cout << "flip 后: ";
for (bool b : vb)
{
std::cout << b << " ";
}
std::cout << "\n";
// 工程建议:如不需要极致空间,可用 vector<char> 替代以避免代理引用坑
}
// ============================================================
int main()
{
std::cout << "========== std::vector 全用法工程化演示 ==========\n";
demo_constructors();
demo_element_access();
demo_iterators();
demo_capacity();
demo_modifiers();
demo_algorithms();
demo_non_member();
demo_2d_vector();
demo_3d_vector();
demo_best_practices();
demo_vector_bool();
std::cout << "\n========== 演示完成 ==========\n";
return 0;
}
更多推荐




所有评论(0)