C++核心编程之Vector容器

embedded/2025/3/5 9:47:34/

C++ vector容器详解:从基础到实战应用

引言

        在C++ STL(标准模板库)中,vector是最常用的动态数组容器之一。它结合了数组的高效随机访问和动态扩展的灵活性,是处理动态数据集合的利器。本文将深入剖析vector的各个核心功能,并通过代码示例和扩展分析,帮助读者全面掌握其使用方法及注意事项。

1. vector基本概念

功能
        vector 是一个动态数组,支持在尾部高效插入和删除元素,同时允许随机访问元素。它的数据结构和数组非常类似,也称为单端数组

与普通数组的区别:

  • 普通数组大小固定,而vector动态扩展
  • 动态扩展机制:当容量不足时,vector会申请更大的内存空间(通常是原容量的2倍),拷贝原有元素并释放旧空间。这一过程会导致迭代器、指针和引用失效。
特性普通数组vector容器
内存管理静态固定大小动态扩展
越界检查at()方法提供
功能扩展丰富的内置方法
内存效率略低(有管理开销)
使用便捷性

  • [动态扩展并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间。
  • [迭代器]vector的迭代器是随机访问迭代器,支持快速随机访问容器中的元素。

2. vector构造函数

2.1 常用构造函数

  • 默认构造函数vector<T> v;                            创建一个空的vector
  • 区间构造函数vector(v.begin(), v.end()); 通过另一个vector的区间来初始化。
  • 填充构造函数vector(n, elem);                     创建一个包含nelem元素的vector
  • 拷贝构造函数vector(const vector &vec);   通过另一个vector来初始化。

2.2 示例代码

#include<iostream>
using namespace std;
#include<vector>// vector 构造函数
void Print(vector<int> &v)
{   for(vector<int>::iterator it=v.begin();it!=v.end(); it++){cout<<*it<<" ";}cout<<endl;
}void test01()
{vector<int>v1;  // 默认构造  无参构造for(int i=0;i<10;i++){v1.push_back(i);}Print(v1);// 通过区间方式进行构造vector<int>v2(v1.begin(), v1.end());Print(v2);//n个elem方式构造vector<int>v3(10,100);Print(v3);// 拷贝构造vector<int>v4(v3);Print(v4);}int main()
{test01();system("pause");return 0;
}

总结:vector提供了多种构造函数,用户可以根据需要选择合适的构造方式,灵活使用即可。

3. vector赋值操作

        给vector容器进行赋值

3.1 常用赋值操作

  • 重载等号操作符vector& operator=(const vector &vec);
  • assign函数assign(beg, end); 或 assign(n, elem);

3.2 示例代码

#include<iostream>
using namespace std;
#include<vector>// vector 赋值操作
/*
* vector& operator=(const vector &vec); //重载等号操作符
* assign(beg, end);                     //将[beg, end)区间中的数据拷贝赋值给本身。
* assign(n, elem);                      //将n个elem拷贝赋值给本身。
*/void Print(vector<int> &v)
{   for(vector<int>::iterator it=v.begin();it!=v.end(); it++){cout<<*it<<" ";}cout<<endl;
}void test01()
{vector<int>v1;for(int i=0; i<10; i++){v1.push_back(i);}Print(v1);// 赋值vector<int>v2;v2 = v1;Print(v2);// assignvector<int>v3;v3.assign(v1.begin(), v1.end());Print(v3);// n个elem 方式赋值vector<int>v4;v4.assign(10, 100);Print(v4);}int main()
{test01();system("pause");return 0;
}

内存变化说明:

  • 赋值操作会完全替换原有内容
  • 可能触发容量自动调整
  • 旧元素会被正确销毁

总结:vector的赋值操作简单直观,用户可以使用operator=assign函数进行赋值。

4. vector容量和大小操作

        对vector容器的容量和大小操作。

4.1 常用函数

  • empty():判断容器是否为空。
  • capacity():返回容器的容量。
  • size():返回容器中元素的个数。
  • resize(int num):重新指定容器的长度为num,若容器变长,则以默认值填充新位置;如果容器变短,则末尾超出容器长度的元素被删除。
  • resize(int num, elem):重新指定容器的长度为num,若容器变长,则以elem值填充新位置;如果容器变短,则末尾超出容器长度的元素被删除。

4.2 示例代码

#include<iostream>
using namespace std;
#include<vector>// vector 容量和大小void Print(vector<int> &v)
{for(vector<int>::iterator it=v.begin(); it!=v.end(); it++){cout<<*it<<" ";}cout<<endl;
}void test01()
{vector<int>v1;for(int i=0; i<10; i++){v1.push_back(i);}    Print(v1);// 判断容器是否为空if(v1.empty())   // 为真,代表容器为空{cout<<"v1为空"<<endl;}else{cout<<"v1不为空"<<endl;cout<<"v1的容量为:"<<v1.capacity()<<endl;cout<<"v1的大小为:"<<v1.size()<<endl; }// 重新指定大小v1.resize(15, 11);  //利用重载版本,可以指定默认填充    Print(v1);      //如果重新指定的比原来长了,默认用0填充新的位置v1.resize(5);Print(v1);      //如果重新指定的比原来短了,超出的部分会删除
}int main()
{test01();system("pause");return 0;
}

容量与大小的区别:

  • size:当前元素数量(逻辑大小)
  • capacity:实际分配的内存容量(物理大小)

总结:

  • 判断是否为空  --- empty
  • 返回元素个数  --- size
  • 返回容器容量  --- capacity
  • 重新指定大小  ---  resize

5. vector插入和删除操作

5.1 常用函数

  • push_back(ele);                                        //尾部插入元素ele
  • pop_back();                                              //删除最后一个元素
  • insert(const_iterator pos, ele);                 //迭代器指向位置pos插入元素ele
  • insert(const_iterator pos, int count,ele);  //迭代器指向位置pos插入count个元素ele
  • erase(const_iterator pos);                       //删除迭代器指向的元素
  • erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素
  • clear();                                                             //删除容器中所有元素

5.2 示例代码

#include<iostream>
using namespace std;
#include<vector>
// vector 插入和删除
/*push_back(ele);                                  //尾部插入元素elepop_back();                                      //删除最后一个元素insert(const_iterator pos, ele);                 //迭代器指向位置pos插入元素eleinsert(const_iterator pos, int count,ele);       //迭代器指向位置pos插入count个元素eleerase(const_iterator pos);                       //删除迭代器指向的元素erase(const_iterator start, const_iterator end); //删除迭代器从start到end之间的元素clear();                                         //删除容器中所有元素
*/
void Print(vector<int> &v)
{for(vector<int>::iterator it=v.begin(); it!=v.end();it++){cout<<*it<<" ";}cout<<endl;
}void test01()
{vector<int>v1;// 尾插法v1.push_back(9);v1.push_back(10);v1.push_back(34);v1.push_back(98);v1.push_back(135);Print(v1);// 尾删法v1.pop_back();Print(v1);// 插入     第一个参数是迭代器v1.insert(v1.begin(), 99);Print(v1);v1.insert(v1.begin(), 3, 100);Print(v1);// 删除   参数是迭代器v1.erase(v1.begin());Print(v1);// 清空// v1.erase(v1.begin(), v1.end());v1.clear();Print(v1);}int main()
{test01();system("pause");return 0;
}

性能注意事项:

  1. 尾部操作时间复杂度O(1)
  2. 中间插入/删除为O(n)
  3. 频繁插入建议使用list

总结:

  • 尾插  --- push_back
  • 尾删  --- pop_back
  • 插入  --- insert    (位置迭代器)
  • 删除  --- erase  (位置迭代器)
  • 清空  ---  clear  

6. vector数据存取

6.1 常用函数

  • at(int idx):返回索引idx所指的数据。
  • operator[]:返回索引idx所指的数据。
  • front():返回容器中第一个元素。
  • back():返回容器中最后一个元素。

6.2 示例代码

#include<iostream>
using namespace std;
#include<vector>// vector 存取void test01()
{vector<int>v1;for(int i=0; i<10; i++){v1.push_back(i);}// 利用[]方式访问数组中元素for(int i=0; i<v1.size();i++){cout<<v1[i]<<" ";}cout<<endl;// 利用at方式访问数组中元素for(int i=0;i<v1.size();i++){cout<<v1.at(i)<<" ";}cout<<endl;// 获取第一个元素cout<<"第一个元素为:"<<v1.front()<<endl;// 获取最后一个元素cout<<"最后一个元素为:"<<v1.back()<<endl;}int main()
{test01();system("pause");return 0;
}

7. vector互换容器

7.1 功能

swap(vec)函数用于交换两个vector容器的内容。

7.2 示例代码

#include<iostream>
using namespace std;
#include<vector>void Print(vector<int> &v)
{for(vector<int>::iterator it=v.begin(); it!=v.end();it++){cout<<*it<<" ";}cout<<endl;
}// vector 互换容器
// 1.基本使用
void test01()
{vector<int>v1;for(int i=0; i<10;i++){v1.push_back(i);}cout<<"交换前:"<<endl;Print(v1);vector<int>v2;for(int i=10; i>0;i--){v2.push_back(i);}Print(v2);cout<<"交换后:"<<endl;v1.swap(v2);Print(v1);Print(v2);}
// 2.实际用途
// 巧用swap可以收缩内存空间
void test02()
{vector<int>v;for(int i=0;i<100000;i++){v.push_back(i);}cout<<"v的容量为:"<<v.capacity()<<endl;cout<<"v的大小为:"<<v.size()<<endl;v.resize(10);  // 重新指定大小cout<<"v的容量为:"<<v.capacity()<<endl;cout<<"v的大小为:"<<v.size()<<endl;// 巧用swap收缩内存vector<int>(v).swap(v);cout<<"v的容量为:"<<v.capacity()<<endl;cout<<"v的大小为:"<<v.size()<<endl;}int main()
{test01();test02();system("pause");return 0;
}

总结:swap可以使两个容器互换,可以达到实用的收缩内存效果。

7.3 内存收缩(swap技巧)

vector<int>(v).swap(v); // 匿名对象技巧

原理分析:

  1. 创建临时匿名vector对象
  2. 利用拷贝构造函数进行元素拷贝
  3. 交换新旧vector的内容
  4. 临时对象析构释放多余内存

8. vector预留空间

8.1 功能

reserve(int len)函数用于预留容器的容量,减少动态扩展的次数。

8.2 示例代码

#include<iostream>
using namespace std;
#include<vector>
// vector 预留空间void test01()
{vector<int>v;// 利用reserve预留空间v.reserve(100000);int num = 0;  // 统计开辟次数int *p = NULL;for(int i=0; i<100000; i++){v.push_back(i);if(p!=&v[0]){p = &v[0];num++;}}cout<<"num = "<< num<<endl;}int main()
{test01();system("pause");return 0;
}

8.3 预分配内存(reserve)

v.reserve(100000); // 预先分配内存

适用场景:

  • 已知元素大致数量时
  • 需要大量push_back操作时
  • 避免频繁内存重新分配

总结:reserve函数可以有效减少vector在动态扩展时的内存分配次数,提升性能。如果数据量较大,可以一开始利用reserve预留空间。

9. 实战应用技巧

9.1 性能优化

  • 尽量使用emplace_back代替push_back
  • 预分配足够内存减少扩容次数
  • 排序时考虑使用算法库的sort
  • 避免在循环中反复resize

9.2 常见陷阱

  1. 迭代器失效问题

    • 插入/删除操作可能导致迭代器失效
    • 解决方案:操作后重新获取迭代器
  2. 越界访问

    // 错误示例
    for(int i=0; i<=v.size(); ++i) cout << v[i]; // 可能越界
    
  3. 浅拷贝问题

    vector<string*> v1;
    vector<string*> v2 = v1; // 指针拷贝,非深拷贝

9.3 最佳实践

  • 遍历优先使用迭代器或范围for循环
  • 需要逆序访问时使用rbegin/rend
  • 结合算法库使用能提升效率
  • 大数据量处理时考虑内存预分配

10. 与其他容器对比

特性vectordequelist
内存结构单端连续多段连续非连续
随机访问O(1)O(1)O(n)
头部插入O(n)O(1)O(1)
尾部插入O(1)O(1)O(1)
中间插入O(n)O(n)O(1)
迭代器类型随机访问随机访问双向
内存预分配支持支持不支持

选型建议:

  • 需要随机访问 → vector/deque
  • 频繁中间插入 → list
  • 内存敏感场景 → array
  • 先进先出队列 → deque

11. 总结与展望

        vector作为STL中最基础的容器,其高效的内存管理和便捷的操作接口使其成为C++开发者的首选容器。理解其底层实现机制对于编写高性能代码至关重要。关键要点总结:

  1. 动态扩展机制:理解capacity和size的关系
  2. 迭代器失效:掌握容器修改后的正确使用方式
  3. 内存优化:合理使用reserve和swap技巧
  4. 算法结合:善用STL算法提升开发效率

        随着C++标准的演进,vector的功能也在不断增强。C++17引入的emplace系列方法、C++20的范围操作等新特性,都使得vector的使用更加高效和安全。建议持续关注STL的发展动态,及时掌握新特性的使用方法。


http://www.ppmy.cn/embedded/170150.html

相关文章

springBoot集成emqx 实现mqtt消息的发送订阅

介绍 我们可以想象这么一个场景&#xff0c;我们java应用想要采集到电表a的每小时的用电信息&#xff0c;我们怎么拿到电表的数据&#xff1f;一般我们会想 直接 java 后台发送请求给电表&#xff0c;然后让电表返回数据就可以了&#xff0c;事实上&#xff0c;我们java应用发…

CentOS7 安装Redis 6.2.6 详细教程

本文主要介绍CentOS7系统下安装Redis6.2.6的详细教程。 1.安装依赖 redis是基于C语言开发&#xff0c;因此想要在服务器上运行redis需要验证是否安装了gcc&#xff0c;没有安装gcc则需先安装 查看是否安装gcc gcc -v如果没有安装gcc&#xff0c;则通过如下命令安装 yum in…

每天练打字17:连续两天赛文速度突破100,今日赛文速度83.01

今日跟打&#xff1a;1932字 总跟打&#xff1a;221584字 记录天数&#xff1a;2602天 &#xff08;实际没有这么多天&#xff0c;这个是注册账号的天数&#xff09; 平均每天&#xff1a;85字 今日赛文首打速度&#xff1a;83.01 上周定的目标是&#xff1a;练习常用字前500&…

【封闭式】论文写作技巧--集中学习+集中写作

学术论文写作是许多科研人员、研究生以及青年学者都会面临的重要挑战。从选题的确定到创新点的挖掘&#xff0c;再到最终成稿&#xff0c;每一步都需要逻辑清晰、方法科学和语言精准。然而&#xff0c;繁重的科研任务和有限的指导资源让许多人在论文写作过程中感到迷茫。为了解…

abseil-cpp:环境搭建

参考: https://abseil.io/docs/cpp/quickstart-cmake abseil-cpp.git/dd4c89b abseil-cpp.git/20240722.1 1. clone代码仓库、编译 git clone https://github.com/abseil/abseil-cpp.git /app/abseil-cpp/ #/app/abseil-cpp/.git/config git checkout 20240722.1git rev-pa…

在笔记本电脑上用DeepSeek搭建个人知识库

最近DeepSeek爆火&#xff0c;试用DeepSeek的企业和个人越来越多。最常见的应用场景就是知识库和知识问答。所以本人也试用了一下&#xff0c;在笔记本电脑上部署DeepSeek并使用开源工具搭建一套知识库&#xff0c;实现完全在本地环境下使用本地文档搭建个人知识库。操作过程共…

el-table 手动选择展示列

需求&#xff1a; 由于表格的列过多,用滚动条进行滚动对比数据不方便&#xff0c;所以提出&#xff0c;手动选择展示列 实现思路&#xff1a; 表格默认展示所有字段&#xff0c;每个字段通过 v-if 属性来进行判断是否显示&#xff1b;点击设置按钮图标(表格右上角&#xff0…

Android NDK图像处理技术指南

Android NDK在图像处理方面的应用。首先&#xff0c;我得确认他们对NDK的基础知识是否了解。可能他们有一定的Android开发经验&#xff0c;但不太熟悉NDK部分。所以&#xff0c;我应该先简要介绍NDK是什么&#xff0c;以及为什么在图像处理中使用它&#xff0c;比如性能优势&am…