STL:vector的常用接口使用及底层讲解和实现

目录

1.vector的介绍及使用

1.1 vector的介绍

1.2 vector的使用

1.2.1vector的构造

1.2.2 vector iterator 的使用

1.2.3vector的空间增长问题

1.2.3 vector 增删查改

1.2.4vector 迭代器失效问题。(重点)

2.vector深度剖析及模拟实现

2.2 动态二维数组理解


1.vector的介绍及使用

1.1 vector的介绍

vector的文档介绍:https://cplusplus.com/reference/vector/vector/

1.2 vector的使用

1.2.1vector的构造

构造函数功能
vector()(重点)无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x); (重点) 拷贝构造
vector (InputIterator first, InputIterator last); 使用迭代器进行初始化构造(可以用于其他容器构造vector)

1.2.2 vector iterator 的使用

接口功能
begin()+end()begin()获取第一个数据位置的iterator/const_iterator, end()获取最后一个数据的下 一个位置的iterator/const_iterator
rbegin()+rend()rbegin()获取最后一个数据位置的reverse_iterator,rend()获取第一个数据前一个位置 的reverse_iterator

1.2.3vector的空间增长问题

1.size()函数,获取数据个数

函数原型:size_type size() const;

2.capacity()函数,获取容量大小

函数原型:size_type capacity() const;

3.empty()函数,判空,空返回true,否则返回false

函数原型:bool empty() const;

4.resize()函数,

函数原型:void resize (size_type n, value_type val = value_type());

  如果n<size()会保留前n个元素删除其他多余的元素,

   如果n>size()则会插入元素使size()达到n个,若指定val就会填充val

   如果n>capacity()则会重新分配空间使size()=capacity()=n

5.reserve()函数

函数原型:void reserve (size_type n);

如果n<capactiy()什么都不变

如果n>capacity(),则会重新分配空间使capacity()=n。

注:capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2 倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体需求定义的。vs是PJ版本STL,g++是SGI版本STL。

reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。

resize在开空间的同时还会进行初始化,影响size。

// 测试vector的默认扩容机制 void TestVectorExpand() { 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'; } } } 

1.2.3 vector 增删查改

1.push_back(),尾插

函数原型:void push_back (const value_type& val);

2.pop_back(),尾删

函数原型 void pop_back();

3.find()(注意这个是算法模块实现,不是vector的成员接口),查找

函数原型:InputIterator find (InputIterator first, InputIterator last, const T& val);

使用时使用迭代器传一个区间和要查找的值,区间左闭右开[first,last),若区间有要查找的值则返回值所在的迭代器,若没有则返回last

4.insert()插入

函数原型:iterator insert (iterator position, const value_type& val);void insert (iterator position, size_type n, const value_type& val);void insert (iterator position, InputIterator first, InputIterator last);

在position位置前插入val;

在position位置前插入n个val;

在position位置前插入一个区间的值,区间左闭右开;

insert()插入改变size()大小,同时如果插入数量多余capacity()剩余空间就会分配新空间这会导致迭代器失效,同时因为vector底层是数组所以插入需要每个数据后移代码效率较低

5.erase() 删除

函数原型: iterator erase (iterator position); iterator erase (iterator first, iterator last);

 删除position位置的元素

 删除一个区间的元素,区间左开右闭

 erase改变size()大小,同时删除后的元素需要前移,迭代器失效同时效率较低

6.swap() 交换

函数原型:template <class T, class Alloc>void swap (vector<T,Alloc>& x, vector<T,Alloc>& y);

容器x的内容与y容器的内容物交换。两个容器对象必须具有相同类型(相同的模板参数),尽管大小可能不同。与算法中实现的swap效果相同

// swap (vector overload) #include <iostream> #include <vector> main () { unsigned int i; std::vector<int> foo (3,100); // three ints with a value of 100 std::vector<int> bar (5,200); // five ints with a value of 200 foo.swap(bar); std::cout << "foo contains:"; for (std::vector<int>::iterator it = foo.begin(); it!=foo.end(); ++it) std::cout << ' ' << *it; std::cout << '\n'; std::cout << "bar contains:"; for (std::vector<int>::iterator it = bar.begin(); it!=bar.end(); ++it) std::cout << ' ' << *it; std::cout << '\n'; return 0; }

7.operator[]

函数原型: reference operator[] (size_type n); const_reference operator[] (size_type n) const;

返回向量容器中位置 n 的元素的引用。一个类似的成员函数vector::at与该算符函数行为相同,但vector::at是边界检查的,通过抛出out_of_range异常来表示请求位置超出范围。所以要注意n 不要超过边界

1.2.4vector 迭代器失效问题。(重点)

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

1.会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、 assign、push_back等。

#include <iostream> using namespace std; #include <vector> int main() {    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;    return 0; } 

2. 指定位置元素的删除操作--erase

#include <iostream> using namespace std; #include <vector> int main() { 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; // 此处会导致非法访问 return 0; } 

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

3. 与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效

#include <string> void TestString() { 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; } } 

2.vector深度剖析及模拟实现

vector常用接口的代码实现

#pragma once #include<assert.h> #include <iostream> #include <algorithm> #include<vector> #include<list> #include<string> using namespace std; namespace lyp { template<class T> class vector { public: typedef T* iterator; typedef const T* const_iterator; vector() = default; vector(const vector<T>& v) { reserve(v.size()); for (int i = 0; i < size(); i++) { push_back(v[i]); } } vector<T>& operator=(vector<T> v) { swap(v); return *this; } void swap(vector<T>& v) { std::swap(_start, v._start); std::swap(_finish, v._finish); std::swap(_end_of, v._end_of); } /*template<class Iterator> vector(Iterator first, Iterator last) { while (first!=last) { push_back(*first); first++; } }*/ //迭代器区间构造 /*template<class inputIterator> vector(inputIterator first, inputIterator last) { while (first != last) { push_back(*first); first++; } }*/ vector(size_t n, const T& val = T()) { reserve(n); for (int i = 0; i < n; i++) { push_back(val); } } /*vector(int n, const T& val = T()) { reserve(n); for (int i = 0; i < n; i++) { push_back(val); } }*/ ~vector() { if (_start) { delete[] _start; _start = _finish = _end_of = nullptr; } } iterator begin() { return _start; } iterator end() { return _finish; } T& operator[](size_t n) { return *(_start + n); } const T& operator[](size_t i) const { assert(i < size()); return _start[i]; } bool empty() { return _start == _finish; } void reserve(size_t n) { if (n > capacity()) { size_t old_size = size(); T* tmp = new T[n]; for (int i = 0; i < size(); i++) { tmp[i] = _start[i]; } delete[] _start; _start = tmp; _finish = tmp + old_size; _end_of = tmp + n; } } void resize(size_t n,T val=T()) { if (n < size()) { _finish = _start + n; } else { //reserve(n); while (_finish < _start + n) { *_finish = val; ++_finish; /*push_back(val);*/ } } } void push_back(const T& val) { if (_finish == _end_of) { reserve(capacity() == 0 ? 4 : capacity() * 2); } *_finish = val; _finish++; } void pop_back() { assert(!empty()); _finish--; } iterator insert(iterator pos, const T& x) { assert(pos<_finish && pos>_start); if (_finish == _end_of) { size_t n = pos - _start; reserve(capacity() == 0 ? 4 : capacity * 2); pos = _start + n; } int i = 0; while (pos + i < _finish) { *(_finish - i - 1) = *(_finish - i); i++; } *pos = x; _finish++; return pos; } void erase(iterator pos) { assert(!empty()); assert(pos<_finish && pos>_start); int i = 0; while (pos + i < _finish) { *(pos + i) = *(pos + 1 + i); i++; } _finish--; } T* data() { return _finish; } int size()const { return _finish - _start; } int capacity() { return _end_of - _start; } private: T* _start = nullptr; T* _finish = nullptr; T* _end_of = nullptr; }; template<class T> void print_T(T& val) { for (auto& e : val) { cout << e << " "; } cout << endl; } void test_vector1() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); for (size_t i = 0; i < v.size(); i++) { cout << v[i] << " "; } cout << endl; vector<int>::iterator it = v.begin(); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; for (auto e : v) { cout << e << " "; } cout << endl; print_T(v); vector<double> vd; vd.push_back(1.1); vd.push_back(2.1); vd.push_back(3.1); vd.push_back(4.1); vd.push_back(5.1); print_T(vd); } void test_vector2() { std::vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); print_T(v); /*v.insert(v.begin() + 2, 30); print_vector(v);*/ int x; cin >> x; auto p = find(v.begin(), v.end(), x); if (p != v.end()) { // insert以后p就是失效,不要直接访问,要访问就要更新这个失效的迭代器的值 /*v.insert(p, 20); (*p) *= 10;*/ p = v.insert(p, 40); (*(p + 1)) *= 10; } print_T(v); } void test_vector3() { std::vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); print_T(v); // 删除所有的偶数 auto it = v.begin(); while (it != v.end()) { if (*it % 2 == 0) { it = v.erase(it); } else { ++it; } } print_T(v); v.reserve(20); print_T(v); } void test_vector4() { int i = int(); int j = int(1); int k(2); vector<int> v; v.resize(10, 1); print_T(v); v.reserve(20); print_T(v); cout << v.size() << endl; cout << v.capacity() << endl; v.resize(15, 2); print_T(v); v.resize(25, 3); print_T(v); v.resize(5); print_T(v); } void test_vector5() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); print_T(v1); vector<int> v2 = v1; print_T(v2); vector<int> v3; v3.push_back(10); v3.push_back(20); v3.push_back(30); v1 = v3; print_T(v1); print_T(v3); } void test_vector6() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(4); v1.push_back(4); /*vector<int> v2(v1.begin(), v1.begin() + 3); print_T(v1); print_T(v2);*/ list<int> lt; lt.push_back(10); lt.push_back(10); lt.push_back(10); lt.push_back(10); /*vector<int> v3(lt.begin(), lt.end());*/ print_T(lt); /*print_T(v2);*/ vector<string> v4(10, "1111111"); print_T(v4); vector<int> v5(10); print_T(v5); vector<int> v6(10u, 1); print_T(v6); vector<int> v7(10, 1); print_T(v7); } void test_vector7() { vector<string> v; v.push_back("11111111111111111111"); v.push_back("11111111111111111111"); v.push_back("11111111111111111111"); v.push_back("11111111111111111111"); print_T(v); v.push_back("11111111111111111111"); print_T(v); } } 

2.2 动态二维数组理解

// 以杨慧三角的前n行为例:假设n为5 void test2vector(size_t n) { // 使用vector定义二维数组vv,vv中的每个元素都是vector<int> bit::vector<bit::vector<int>> vv(n);        // 将二维数组每一行中的vecotr<int>中的元素全部设置为1 for (size_t i = 0; i < n; ++i) vv[i].resize(i + 1, 1);    // 给杨慧三角出第一列和对角线的所有元素赋值 for (int i = 2; i < n; ++i) { for (int j = 1; j < i; ++j) { vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1]; } } }

bit::vector> vv(n); 构造一个vv动态二维数组,vv中总共有n个元素,每个元素 都是vector类型的,每行没有包含任何元素,如果n为5时如下所示:

Read more

FARS全自动科研系统技术深度解析:从多智能体架构到工业化科研范式

FARS全自动科研系统技术深度解析:从多智能体架构到工业化科研范式

前言 2026年2月12日至2月22日,一场持续228小时33分钟的直播在全球AI社区引发了持续震荡。屏幕另一端,一个名为FARS(Fully Automated Research System)的全自动研究系统,在没有人类干预的情况下,自主完成了从文献调研到论文撰写的完整科研流程,最终产出100篇学术论文,总消耗114亿Token,成本10.4万美元。 这场实验的意义远不止于“AI写论文”的简单升级。它向世界展示了科学发现的根本范式正在发生转移——从依赖人类灵感的“手工作坊”,转向由AI驱动的“工业化流水线”。本文将从最底层的技术细节出发,逐层拆解FARS的系统架构、智能体协作机制、资源调度策略、成本控制模型,以及与竞品的技术对比,为读者呈现一个完整的全自动科研系统技术图谱。 第一章 系统总体架构:四智能体流水线设计 1.1 核心设计理念:研究系统的第一性原理 FARS的设计并非简单地模仿人类科研流程,而是基于团队对“研究系统”本质的重新思考。创始团队提出,一个理想的研究系统应遵循两条基本原则: 1. 高效拓展知识边界:系统的吞吐量应成为核心评估指标,而非单篇论文的完

By Ne0inhk

一文读懂Spring AOP:手把手教你优雅实现“无侵入”代码增强

目录 1.什么是Spring AOP? 2.SpringAOP优点与上手 Spring AOP 的核心术语 3.通知类型注解 4.@PointCut+@Order 5.切点表达式 6.代理模式 7.Spring AOP原理 1.什么是Spring AOP? AOP=>面向切片编程思想,是一种对一类问题集中处理的思想,比如拦截器,统一返回结果管理,统一异常处理,登录校验......如果使用OOP(面向结果编程)会让相同的代码重复多次出现,业务方法中混杂着非核心的逻辑。 Spring AOP就是为了解决这些问题存在,是AOP思想的其中一种实现方式 2.SpringAOP优点与上手 优点: * 不影响原有代码,解耦 * 便于维护功能 * 提高开发效率 * 减少重复代码 快速上手SpringAOP 编写一个使用SpringAOP计算所有方法的运行时长的例子 1.

By Ne0inhk
Django与模板

Django与模板

我叫补三补四,很高兴见到大家,欢迎一起学习交流和进步 今天来讲一讲视图 Django与模板文件工作流程 模板引擎:主要参与模板渲染的系统。 内容源:输入的数据流。比较常见的有数据库、XML文件和用户请求这样的网络数据。 模板:一般是和语言相关的文本。 工作流程: 作为一个web框架,Django自带了一套模板系统动态生成HTML文本 模板主要包含两个部分:HTML的静态部分和描述如何插入动态内容的特殊语法 模板系统的相关配置 模板的配置也在settings.py当中实现   TEMPLATES = [  # 模板配置变量     {         'BACKEND': 'django.template.backends.django.DjangoTemplates',  # 配置使用自带模板         'DIRS': [  # 配置寻址目录             '/var/www/html/site.com',             '/var/www/html/default&

By Ne0inhk
【OpenClaw从入门到精通】第03篇:吃透Gateway/Skills/ClawHub核心概念(2026实测+避坑)

【OpenClaw从入门到精通】第03篇:吃透Gateway/Skills/ClawHub核心概念(2026实测+避坑)

摘要:本文针对OpenClaw新手易混淆的核心概念痛点,以通俗类比+实操演示拆解OpenClaw核心、Gateway、Skills、ClawHub四大组件。通过“数字员工团队”类比明确各组件定位:OpenClaw核心是“老板”(调度中心)、Gateway是“前台+后勤”(后台进程)、Skills是“专业员工”(功能插件)、ClawHub是“人才市场”(技能商店)。补充版本更名史、技能加载优先级、ClawHub与GitHub区别等关键细节,结合“AI融资新闻查询并邮件推送”虚拟案例演示组件协同流程,梳理5个高频认知误区及解决方案。所有内容基于2026年官方文档实测,案例为虚拟构建,代码仅作示例未上传GitHub,兼顾新手理解与进阶实操参考,帮助读者建立清晰的OpenClaw架构认知。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】

By Ne0inhk