vector

vector

vector

1 vector的介绍

vector是C++标准模板库(STL)中最常用的序列容器之一,封装了动态数组,可以自动管理内存,提供随机访问、动态扩容等功能,可以把vector理解成一个数组。
基本特性
动态数组:
大小可变,插入/删除元素时自动调整容量
连续存储: 元素在内存中连续存放,支持高效的随机访问
类型安全: 模板类,存储特定类型的对象
内存自动管理: 自动分配和释放内存,避免手动new[]/delete[]

2 vector的使用

2.1 vector的定义

#include<iostream>#include<vector>intmain(){ std::vector<int> first;// 空的int类型的vector std::vector<int>second(4,100);// 4个100的int类型的vector std::vector<int>third(second.begin(),second.end());// 拷贝second的begin到end给third std::vector<int>fourth(third);// 拷贝third给fourth// 迭代器构造函数也可以用于从数组构造int myints[]={16,2,77,29}; std::vector<int>fifth(myints, myints +sizeof(myints)/sizeof(int)); std::cout <<"fifth的内容是:";for(std::vector<int>::iterator it = fifth.begin(); it != fifth.end();++it) std::cout <<' '<<*it; std::cout <<'\n';//输出的内容是 16 2 77 29return0;}

默认构造函数:创建一个空vector,无元素,容量为0

std::vector<int> v1;// 空 vector

指定大小构造:创建包含n个元素的vector,每个元素的值为默认初始化的值(对于int是0)

std::vector<int>v2(5);// 5 个元素,均为 0

指定大小和初始值构造:创建包含n个元素的vector,每个元素都初始化为value

std::vector<int>v3(5,10);// 5 个元素,均为 10

列表初始化:使用花括号直接列出元素值,也是最直观的方式

std::vector<int> v4 ={1,2,3,4,5}; std::vector<int> v5 {1,2,3,4,5};// 等价

拷贝构造函数:用一个已有的vector构造新vector,深拷贝所有元素

std::vector<int>v6(v4);// v6 是 v4 的副本 std::vector<int> v7 = v4;// 等价

范围构造函数:用一个容器或数组的迭代器区间[first,last)构造,元素类型需可转换

std::vector<int>v8(v4.begin(), v4.end());// 从 vector 拷贝int arr[]={10,20,30}; std::vector<int>v9(std::begin(arr), std::end(arr));// 从数组拷贝

注意事项

  • 圆括号和花括号的区别:
    vector v(5, 10) → 5 个元素,值为 10。
    vector v{5, 10} → 2 个元素,值为 5 和 10(列表初始化优先)
    这是最容易被混淆的地方
  • 范围构造要求:迭代器区间必须是合法的,且元素类型需能隐式转换为vector的元素类型

2.2 vector iterator的使用

begin和end: 获取第一个数据位置的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator
rbegin和rend: 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator

在这里插入图片描述

2.3 vector空间

size() 获取元素个数
返回当前vector中实际存储的元素个数

std::vector<int> v ={1,2,3}; std::cout << v.size();// 输出 3

capacity() 获取当前已分配内存能容纳的元素个数
返回在不重新分配内存的前提下,vector最多可以存储的元素个数
通常capacity() >= size()

std::vector<int> v; v.reserve(10);// 容量至少为10 std::cout << v.capacity();// 可能输出10 std::cout << v.size();// 输出0

注意,capacity是内存容量,size是实际元素个数,插入元素使size超过capacity时,vector会自动扩容

empty() 判断是否为空
如果size() == 0 则返回true,否则返回false

std::vector<int> v;if(v.empty()){/* 空时执行 */}

resize() 改变size

voidresize(size_type new_size);voidresize(size_type new_size,const value_type& value);

将vector的元素个数改为new_size
如果new_size < 原size ,删除多余元素,从尾部删除
如果new_size > 原size ,在尾部添加新元素
如果没有第二个参数时,新元素为值初始化
提供value时,新元素均为value的拷贝

std::vector<int> v ={1,2,3}; v.resize(5);// 现在 v = {1,2,3,0,0},若容量不足则扩容 v.resize(2);// v = {1,2},尾部元素被丢弃 v.resize(4,100);// v = {1,2,100,100}

reserve() 改变capacity

voidreserve(size_type new_cap);

请求将vector的容量至少增加至new_cap(预分配内存)
如果new_cap > 当前 capacity(),则重新分配内存使 capacity() >= new_cap
如果new_cap <= 当前 capacity(),什么也不做(不会减少容量)

std::vector<int> v; v.reserve(1000);// 容量至少1000,size仍为0for(int i =0; i <1000;++i) v.push_back(i);// 这1000次插入不会发生扩容
  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容代价缺陷问题
  • resize在开空间的同时还会进行初始化,影响size
voidTestVectorExpand(){ size_t sz; vector<int> v; sz = v.capacity(); cout <<"making v grow:\n";for(int i =0; i <100;++i){ v.push_back(i);if(sz != v.capacity()){ sz = v.capacity(); cout <<"capacity changed: "<< sz <<'\n';}}}

2.4 vector增删查改

push_back() 在容器的末尾添加一个元素
当容量不足时,会重新分配内存

voidpush_back(const T& value);voidpush_back(T&& value);

pop_back() 删除容器末尾的一个元素
调用前需要确保vector非空,否则行为未定义
被删除元素的后置迭代器/引用会失效,end()也会失效

voidpop_back();

find() 在指定范围内查找第一个给定值的元素
返回指向第一个匹配元素的迭代器,若未找到,返回last
头文件 < algorithm >

InputIt find(InputIt first, InputIt last,const T& value);

insert() 在指定位置之前插入一个或多个元素
返回指向第一个插入元素的迭代器,若插入个数为0,则返回pos
如果容量不足会重新分配内存,导致所有迭代器,引用,指针失效
如果没有重新分配,则插入位置之后的元素会向后移动,这些元素的迭代器会失效

iterator insert(const_iterator pos,const T& value);// 插入一个副本 iterator insert(const_iterator pos, T&& value);// 插入一个移动副本 iterator insert(const_iterator pos, size_type count,const T& value);// 插入 count 个相同值template<classInputIt> iterator insert(const_iterator pos, InputIt first, InputIt last);//插入一段区间

erase() 删除指定位置或指定区间内的元素
返回指向被删除元素之后下一个元素的迭代器,如果删除到末尾,则返回end()
删除位置之后的所有元素会向前移动,其迭代器,引用会失效
不会重新分配内存,容量不变

iterator erase(const_iterator pos);// 删除单个元素 iterator erase(const_iterator first, const_iterator last);// 删除 [first, last) 区间

swap() 交换两个vector的内容
不会引发内存分配或者元素复制,只是交换内部指针
交换后,两个vector的迭代器,引用,指针会相互归属到对方容器
提供非成员swap()特化,用法:swap(v1, v2);

voidswap(vector& other);

operator[] 通过下标访问元素
不检查下标是否越界,越界会导致未定义行为,通常表现为内存访问错误
如果需要安全访问时,可以使用at() 成员函数

reference operator[](size_type pos); const_reference operator[](size_type pos)const;

2.5 迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生指针T*。因此迭代器失效,实际就是迭代器底层对应的指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果就是程序崩溃,也就是说如果继续使用已经失效的迭代器,程序可能崩溃

  • 会引起底层空间改变的操作,都有可能让迭代器失效,比如:resize、reserve、insert、assign、push_back
#include<iostream>usingnamespace std;#include<vector>intmain(){ vector<int> v{1,2,3,4,5,6};auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变// v.assign(100, 8);/* 出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉, 而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时, 实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。 解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素, 只需给it重新赋值即可。 */while(it != v.end()){ cout<<*it <<" ";++it;} cout<<endl;return0;}
  • 指定位置元素的删除操作 erase
#include<iostream>usingnamespace std;#include<vector>intmain(){int a[]={1,2,3,4}; vector<int>v(a, a +sizeof(a)/sizeof(int));// 使用find查找3所在位置的iterator vector<int>::iterator pos =find(v.begin(), v.end(),3);// 删除pos位置的数据,导致pos迭代器失效。 v.erase(pos); cout <<*pos << endl;// 此处会导致非法访问return0;}

erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上将迭代器不会失效,但是如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了,因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了

下面这段代码的效果是删除vector中的偶数

#include<iostream>usingnamespace std;#include<vector>//这一段代码调用erase之后,it已经失效,但是仍然对it进行++操作,会导致报错intmain(){ vector<int> v{1,2,3,4};auto it = v.begin();while(it != v.end()){if(*it %2==0) v.erase(it);++it;}return0;}//这一段代码调用erase之后,通过erase的返回值重新覆盖了it,所以it没有失效,不会报错intmain(){ vector<int> v{1,2,3,4};auto it = v.begin();while(it != v.end()){if(*it %2==0) it = v.erase(it);else++it;}return0;}
  • vector相似,string在插入+扩容之后,迭代器也会失效
#include<string>voidTestString(){ string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while(it != s.end()){ cout <<*it;++it;} cout << endl; it = s.begin();while(it != s.end()){ it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it); ++it;}}

Read more

SpringAI 大模型应用开发篇-SpringAI 项目的新手入门知识

SpringAI 大模型应用开发篇-SpringAI 项目的新手入门知识

🔥博客主页: 【小扳_-ZEEKLOG博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 SpringAI 概述         1.1 大模型的使用         2.0 SpringAI 新手入门         2.1 配置 pom.xml 文件         2.2 配置 application.yaml 文件         2.3 配置 ChatClient         2.4 同步调用         2.5 流式调用         2.6 System 设定         2.7 日志功能         2.8 会话记忆功能

最新更新版本,OpenClaw v2026.4.2 深度解读剖析:Task Flow 重磅回归与安全架构的全面硬化

最新更新版本,OpenClaw v2026.4.2 深度解读剖析:Task Flow 重磅回归与安全架构的全面硬化

文档版本:v1.0 分析基准日期:2026年4月3日 字数统计:约20,000字 分析维度:架构演进、功能解析、安全机制、生态影响、升级指南、未来展望 第一章:版本总览——一次功能与安全并重的里程碑式更新 1.1 发布背景与战略定位 2026年4月3日,OpenClaw 正式发布 v2026.4.2 版本。这并非一次常规的迭代更新,而是在经历了2026年3月一系列架构大手术(v2026.3.7 的 ContextEngine 插件化、v2026.3.31 的核心架构重塑)之后,项目进入**"能力回归与安全硬化"**阶段的关键里程碑。 从版本号演进来看,v2026.4.2

Python + Selenium + AI 智能爬虫:自动识别反爬与数据提取

Python + Selenium + AI 智能爬虫:自动识别反爬与数据提取

结合 Selenium 浏览器自动化与 AI 大模型能力,构建能够自动识别反爬机制、智能解析页面的新一代爬虫系统。 1. 系统架构 验证码 登录墙 正常页面 种子 URL 队列 调度器 Selenium WebDriver 反检测模块 页面渲染 AI 反爬识别 AI 验证码破解 自动登录 AI 数据提取 数据清洗管道 存储 MongoDB / CSV 数据看板 2. 反爬机制分布 35%25%20%10%7%3%常见反爬机制占比(Top 500 网站统计)JS 动态渲染请求频率限制验证码(图形/滑块)User-Agent 检测IP