当前位置: 首页 > news >正文

【STL】 vector的底层实现

1.vector的模拟代码完整实现(后面会拆分开一个一个细讲)

#pragma once
#include<assert.h>// 抓重点namespace bit
{/*template<class T>class vector{public:typedef T* iterator;private:T* _a;size_t _size;size_t _capacity;};*/template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}iterator begin(){return _start;}iterator end(){return _finish;}// 类模板的成员函数// 函数模板 -- 目的支持任意容器的迭代器区间初始化template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(size_t n, const T& val = T()) //创建一个包含 n 个元素的向量,并且每个元素都被初始化为 val 的值。//如果没有提供 val 参数,则默认使用 T() 构造出的默认值。{reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}vector(initializer_list<T> il)//vector(initializer_list<T> il):这是 vector 类的构造函数。它允许使用花括号 {} 括起来的一组元素来初始化 vector 对象。{reserve(il.size());for (auto e : il){push_back(e);}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}// 强制编译器生成默认的vector() = default;// v2(v1)vector(const vector<T>& v){reserve(v.capacity());for (auto e : v){push_back(e);}}// 16:05继续void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}// v1 = v3vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}void reserve(size_t n){if (n > capacity()){size_t oldsize = size();T* tmp = new T[n];if (_start){//memcpy(tmp, _start, sizeof(T) * old_size);for (size_t i = 0; i < oldsize; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + oldsize;_end_of_storage = _start + n;}}size_t capacity() const{return _end_of_storage - _start;}size_t size()  const{return _finish - _start;}T& operator[](size_t i){assert(i < size());return _start[i];}const T& operator[](size_t i) const{assert(i < size());return _start[i];}void push_back(const T& x){/*if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;++_finish;*/insert(end(), x);}void pop_back(){assert(size() > 0);--_finish;}iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}// 迭代器// 勿在浮沙筑高台void erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it != _finish){*(it - 1) = *it;++it;}--_finish;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};

2.vector的成员变量

在查看STL库里面vector的实现时,我们发现它是一个类模板并且定义了三个成员变量,分别是iterator start、iterator finish、 iterator end_of_storage用来标记开始,结束,以及总容量,对于vector来说其迭代器iterator就是T*,例如我们之前学习过的顺序表插入的是int类型的数据,所以对存放int类型的vector来说T*就是int*。以此类推,在定义的时候<>里面定义的类型就是容器中所存放的类型  char string list等都可以存放在里面

3.vector中的部分成员变量

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}iterator begin(){return _start;}iterator end(){return _finish;}

4.vector中的构造函数

        1.默认构造

vector():_start(nullptr), _finish(nullptr), _endOfStorage(nullptr)
{}
//上下等价
//vector() = default; //强制编译器生成默认的

        2.拷贝构造

// v2 (v1)
vector(const vector<T>& v)
{reserve(v.capacity());for (auto e : v) push_back(e);
}

        3.迭代器区间初始化

        

//类模板的成员函数,迭代器区间初始化
//函数模板  -- 目的支持任意容器迭代器区间初始化
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{//reserve(last - first);while (first != last){push_back(*first);++first;}
}

        4.n个val构造

//n个val构造
vector(size_t n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象T()
{reserve(n);while(n--){push_back(val);}
}//n个val构造,第一个参数为int类型
vector(int n, const T& val = T())//缺省值不能给0,因为T可能是string,所以给匿名对象
{reserve(n);while(n--){push_back(val);}
}

5.对于构造函数的测试

void test_vector7()
{vector<string> v1(10);vector<string> v2(10, "xxx");for (auto e : v1){cout << e << " ";}cout << endl;for (auto e : v2){cout << e << " ";}cout << endl;vector<int> v3(10,1); //若没有迭代器函数区间匹配,可以将就运行//vector <int> v3(10u, 1); //因为调用的是unsigned那个for (auto e : v3){cout << e << " ";}cout << endl;vector<int> v4(10, 1);for (auto e : v4){cout << e << " ";}cout << endl;
}

6.initializer_list构造

initializer_list是C++新增的一个类型,方便初始化,支持将花括号括起来的值initializer_list,initializer_list对象里面有两个指针,指向花括号里面值开始和结尾的下一个,并支持迭代器,所以可以使用范围for来遍历,当然这个要编译器支持将花括号传给容器

//initializer_list构造
vector(initializer_list<T> il)
{reserve(il.size());//size表示数据个数for (auto i : il){push_back(i);}
}

6.1 initializer_list构造的测试代码

void test_vector8() //initializer_list构造测试
{//隐式类型转换vector<int> v1({ 1,2,3,4,5 });vector<int> v2 = { 6,7,8,9,10 };for (auto e : v1){cout << e << " ";}cout << endl;for (auto e : v2){cout << e << " ";}
}

7.赋值运算符的重载

// v1 = v3
vector<T>& operator = (vector<T> v)
{swap(v);return *this;
}

这里使用传值传参,是实参的拷贝,所以我们将它与被赋值的对象交换后返回即可完成赋值,并且交换后形参生命周期结束就会自动调用析构函数释放原来的空间。

5.vector类中的容量操作

1.size 与 capacity

int main(){cout << "指定⼤⼩为10时:\n";vector<int> v(10, 1);cout << v.size() << endl;cout << v.capacity() << endl;vector<int> v1;v1.push_back(1);v1.push_back(1);v1.push_back(1);v1.push_back(1);cout << "插⼊四个数据时:\n";cout << v1.size() << endl;cout << v1.capacity() << endl;cout << "插⼊五个数据时:\n";v1.push_back(1);cout << v1.size() << endl;cout << v1.capacity() << endl;return 0;}
输出结果:
指定⼤⼩为10时:
1010
插⼊四个数据时:
44
插⼊五个数据时:
58

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

2.resize

resize在开空间的同时还会进⾏初始化,影响size 使⽤resize()函数可以改变调⽤对象的size和capacity⼤⼩,如果指定的⼤⼩⼩于size时相当于删除数据,当指定⼤⼩ ⼤于size时则作⽤为扩容+初始化(对于int默认初始化为0)

int main(){vector<int> v(10, 1);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 1 1 1 1 1 1 1 1 1 
v.resize(20);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 
v.resize(5);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 1 1 1 1 
//指定⼤⼩⼩于当前的size时,再指定初始化内容时不会修改原始内容
v.resize(3, 3);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}//1 1 1return 0;}

3.reserve

reserve只负责开辟空间,如果确定知道需要⽤多少空间,reserve可以缓解vector增容的代价缺陷问题。 使⽤reserve()函数可以更改调⽤对象的capacity的⼤⼩,注意,如果指定⼤⼩⼩于当前的capacity时,则不会做任何 处理

int main(){vector<int> v(10, 1);cout << "原始⼤⼩:\n";cout << v.capacity() << endl;cout << v.size() << endl;cout << "扩容到20:\n";v.reserve(20);cout << v.capacity() << endl;cout << v.size() << endl;cout << "扩容到5:\n";v.reserve(5);cout << v.capacity() << endl;cout << v.size() << endl;return 0;}
输出结果:
原始⼤⼩:
1010
扩容到20:
2010
扩容到5:
2010

6.vector类中的数据遍历操作

void test2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);
//迭代器遍历
//指明迭代器类型
vector<int>::iterator it1 = v.begin();while (it1 != v.end()) {cout << *it1 <<" ";it1++;}cout << endl;//1 2 3 4//下标遍历
for (size_t i = 0; i < v.size(); i++) {cout << v[i] << " ";}cout << endl;//1 2 3 4//范围forfor(auto &e : v){cout << e <<" ";}cout << endl;//1 2 3 4}int main(){test2();}

6.2 operator 与at()函数

6.3 正向遍历begin()和end()迭代器——⾮const

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v(10, 1);//正向迭代器——⾮constvector<int>::iterator it = v.begin();while (it != v.end()){*it = 2;//可修改
cout << *it << " ";it++;}return 0;}
输出结果:
2 2 2 2 2 2 2 2 2 2

6.4逆向遍历rbegin()和rend()迭代器——⾮const

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//逆向迭代器——⾮constvector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){(*rit)++;//可修改
cout << *rit << " ";
rit++;}return 0;}
输出结果:
5 4 3 2

6.5 assign()函数

//使⽤⼀个对象的迭代器区间为调⽤对象分配内容
#include <iostream>#include <vector>using namespace std;int main(){//vector<int> v(5, 1);vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto num : v){cout << num << " ";}
cout << endl;vector<int> v1(10, 2);//v.assign(v1.begin(), v1.end());v.assign(v1.begin(), v1.end());for (auto num : v){cout << num << " ";}return 0;}
输出结果:
1 2 3 42 2 2 2 2 2 2 2 2 2//指定n个内容为调⽤对象分配
#include <iostream>#include <vector>using namespace std;int main(){//vector<int> v(5, 1);vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto num : v){cout << num << " ";}cout << endl;//vector<int> v1;//v1.push_back(5);//v1.push_back(6);//v1.push_back(7);//v1.push_back(8);//v.assign(v1.begin(), v1.end());v.assign(10, 5);for (auto num : v){cout << num << " ";}return 0;}
输出结果:
1 2 3 45 5 5 5 5 5 5 5 5 5

7.插入insert

iterator insert(iterator pos, const T& x)
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){//防止迭代器因为后面的扩容失效,所以要提前记录pos位置size_t len = pos - _start;//size_t len = size();size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len; //判断扩容之后os位置,防止野指针出现使迭代器失效}iterator end = _finish - 1; //后移while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;
}

这里要注意迭代器因为扩容导致pos失效的问题(野指针),所以要提前规避,记录好pos相对位置,然后再即时更新pos迭代器,否则就会出现随机值;

此外,insert的参数pos是对实参的拷贝,形参的改变不会影响实参,所以外部的实参也会失效,但是我们也不能通过引用传参,因为其迭代器返回的是临时拷贝具有常性不能通过引用传参,所以这里我们就可以通过控制insert函数的返回值来解决,我们会返回更新后的迭代器,这样就可以访问该位置了。

7.2push_back可以直接复用insert进行实现

//尾插
void push_back(const T& x)
{insert(end(), x);
}

7.3push_back与pop_back函数的测试

//在指定的的迭代器位置后插⼊内容val#include <iostream>#include <vector>using namespace std;
int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.insert(v.begin() + 3, 5);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}return 0;}
输出结果:
1 2 3 41 2 3 5 4

7.4在指定的迭代器位置后开始插⼊n个val

//在指定的迭代器位置后开始插⼊n个val#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.insert(v.begin() + 3, 5, 10);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}return 0;}
输出结果:
1 2 3 41 2 3 10 10 10 10 10 4

7.5在指定的迭代器位置后开始插⼊⼀个其他对象对应的迭代器区间中的内容

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<double> v1;v1.push_back(5.2);v1.push_back(6.3);v1.push_back(7.4);v1.push_back(8.5);//根据调⽤对象的类型决定强制转换的类型
v.insert(v.begin() + 3, v1.begin(), v1.end());//将double强制转换成int类型存⼊int类型的vector对象
for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v1.insert(v1.begin() + 3, v.begin(), v.end());//将int强制转换成double类型存⼊double类型的vector
对象
}for (size_t i = 0; i < v1.size(); i++){cout << v1[i] << " ";}return 0;
输出结果:
1 2 3 41 2 3 5 6 7 8 45.2 6.3 7.4 1 2 3 5 6 7 8 4 8.5

8.删除erase

iterator erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it != _finish) //从pos + 1开始往前移动{*(it - 1) = *it;++it;}--_finish;return pos;
}

erase()之后迭代器失效问题

  • 有可能删除之后缩容
  • 删除最后一个位置会导致越界访问

所以我们认为删除操作之后迭代器也会失效,和插入函数一样通过返回迭代器来更新迭代器使用才行

8.2 删除指定位置的⼀个数据

//删除指定位置的⼀个数据
#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 2 3 4vector<int>::iterator it = v.begin() + 1;v.erase(it);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 3 4//不可以再删除迭代器⼀开始指向的位置,存在迭代器失效问题
//v.erase(it);//如果还需要删除下标为1的位置需要再将迭代器更新
it = v.begin() + 1;v.erase(it);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";//1 4}return 0;}

8.3 删除迭代器区间中的内容

 //删除迭代器区间中的内容
#include <iostream>#include <vector>
using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 2 3 4v.erase(v.begin() + 2, v.end());for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//1 2return 0;}

9.swap函数

使⽤swap()函数可以交换调⽤对象和指定对象中的数据

#include <iostream>#include <vector>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>    
v1(5, 1);cout << "交换前:\n";cout << "v的size:" << v.size() << endl;//4cout << "v的capacity:" << v.capacity() << endl;//4for (auto num : v){cout << num << " ";}cout << endl;//1 2 3 4cout << "v1的size:" << v1.size() << endl;//5cout << "v1的capacity:" << v1.capacity() << endl;//5
for (auto num : v1){cout << num << " ";}//1 1 1 1 1v.swap(v1);cout << "\n交换后:\n";cout << "v的size:" << v.size() << endl;//5cout << "v的capacity:" << v.capacity() << endl;for (auto num : v){cout << num << " ";}//11111cout << endl;cout << "v1的size:" << v1.size() << endl;//4cout << "v1的capacity:" << v1.capacity() << endl;//4for (auto num : v1){cout << num << " ";}//1234return 0;}

10.find函数

#include <iostream>#include <vector>#include <algorithm>using namespace std;int main(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = find(v.begin(), v.end(), 3);
cout << *it << endl;//3return 0;}

11.某帅哥做的笔记——pdf

vector

相关文章:

【STL】 vector的底层实现

1.vector的模拟代码完整实现&#xff08;后面会拆分开一个一个细讲&#xff09; #pragma once #include<assert.h>// 抓重点namespace bit {/*template<class T>class vector{public:typedef T* iterator;private:T* _a;size_t _size;size_t _capacity;};*/templa…...

责任链模式:解耦职责,优化请求处理

在软件设计中&#xff0c;如何有效地处理复杂的请求是一个重要的课题。 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;提供了一种解耦请求发送者和接收者的方法&#xff0c;使得多个对象都有机会处理请求&#xff0c;从而达到灵活和可扩展的设计。 什么…...

【Scene Transformer】scene transformer论文阅读笔记

文章目录 序言(Abstract)(Introduction)(Related Work)(Methods)(Scene-centric Representation for Agents and Road Graphs)(Encoding Transformer)(Predicting Probabilities for Each Futures)(Joint and Marginal Loss Formulation) (Results)(Discussion)(Questions) sce…...

ESP32在ESP-IDF环境下禁用看门狗

最近使用了一款ESP32的开发板。但在调试时发现出现许多看门狗复位事件&#xff1a; E (8296) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: E (8296) task_wdt: - IDLE (CPU 0) E (8296) task_wdt: Tasks curre…...

基于 uniapp html5plus API,怎么把图片保存到相册

要将图片保存到相册中&#xff0c;可以使用HTML5 API中的plus.gallery.save方法。以下是一个示例代码&#xff0c;展示如何将图片保存到手机相册&#xff1a; // 图片的URL&#xff0c;可以是本地路径或网络路径 var imageUrl path/to/your/image.jpg;// 调用plus.gallery.sa…...

3.特征工程-特征抽取、特征预处理、特征降维

文章目录 环境配置&#xff08;必看&#xff09;头文件引用1.数据集: sklearn代码运行结果 2.字典特征抽取: DictVectorizer代码运行结果稀疏矩阵 3.文本特征抽取(英文文本): CountVectorizer()代码运行结果 4.中文文本分词(中文文本特征抽取使用)代码运行结果 5.中文文本特征抽…...

RISC-V (五)上下文切换和协作式多任务

任务&#xff08;task&#xff09; 所谓的任务就是寄存器的当前值。 -smp后面的数字指的是hart的个数&#xff0c;qemu模拟器最大可以有8个核&#xff0c;此文围绕一个核来讲。 QEMU qemu-system-riscv32 QFLAG -nographic -smp 1 -machine virt -bios none 协作式多任务 …...

Cornerstone加载本地Dicom文件第二弹 - Blob篇

&#x1f340; 引言 当我们刚接触Cornerstone或拿到一组Dicom文件时&#xff0c;如果没有ImageID和后台接口&#xff0c;可能只是想简单测试Cornerstone能否加载这些Dicom文件。在这种情况下&#xff0c;可以使用本地文件加载的方法。之前我们介绍了通过node启动服务器请求文件…...

C语言中整数类型及其类型转换

1.数据的存储和排列 是的&#xff0c;在C语言中&#xff0c;整数类型通常以补码&#xff08;twos complement&#xff09;形式存储在内存中。这是因为补码表示法在处理有符号整数的加减运算上更为简便和高效。 2.有符号数和无符号数之间的转换 在C语言中&#xff0c;有符号数和…...

powerjob连接postgresql数据库(支持docker部署)

1.先去pg建一个powerjob-product库 2.首先去拉最新的包&#xff0c;然后找到server模块&#xff0c;把mysql的配置文件信息替换成pg的 spring.datasource.hikari.auto-committrue spring.datasource.remote.hibernate.properties.hibernate.dialecttech.powerjob.server.pers…...

浅谈位运算及其应用(c++)

目录 一、位运算的基础&#xff08;一&#xff09;位与&#xff08;&&#xff09;&#xff08;二&#xff09;位或&#xff08;|&#xff09;&#xff08;三&#xff09;位异或&#xff08;^&#xff09;&#xff08;四&#xff09;位取反&#xff08;~&#xff09;&#x…...

Git版本管理中下列不适于Git的本地工作区域的是

Git版本管理中下列不适于Git的本地工作区域的是 A. 工作目录 B. 代码区 C. 暂存区 D. 资源库 选择B Git本地有四个工作区域&#xff1a; 工作目录&#xff08;Working Directory&#xff09;、 暂存区(Stage/Index)、 资源库(Repository或Git Directory)、 git仓库(Remote Di…...

webGL + WebGIS + 数据可视化

webGL&#xff1a; 解释&#xff1a;用于在浏览器中渲染 2D 和 3D 图形。它是基于 OpenGL ES 的&#xff0c;提供了直接操作 GPU 的能力。 库&#xff1a; Three.jsBabylon.jsPixiJSReglGlMatrixOsgjs WebGIS&#xff1a; 解释&#xff1a;用于在 Web 浏览器中处理和展示地…...

职场“老油条”的常规操作,会让你少走许多弯路,尤其这三点

有句话说得好&#xff1a;“在成长的路上&#xff0c;要么受教育&#xff0c;要么受教训。” 挨过打才知道疼&#xff0c;吃过亏才变聪明&#xff0c;从职场“老油条”身上能学到很多经验&#xff0c;不一定全对&#xff0c;但至少有可以借鉴的地方&#xff0c;至少能让你少走…...

Ceres Cuda加速

文章目录 一、简介二、准备工作三、实现代码四、实现效果参考资料一、简介 字Ceres2.2.1版本之后,作者针对于稠密矩阵的分解计算等操作进行了Cuda加速,因此这里就基于此项改动测试一下效果。 二、准备工作 1、首先是需要安装Cuda这个英伟达第三方库,https://developer.nvidi…...

微信小程序生成小程序转发链接,携带参数跳转到另外一个页面

🤵 作者:coderYYY 🧑 个人简介:前端程序媛,目前主攻web前端,后端辅助,其他技术知识也会偶尔分享🍀欢迎和我一起交流!🚀(评论和私信一般会回!!) 👉 个人专栏推荐:《前端项目教程以及代码》 ✨一、前言 需求:在页面A生成分享链接(携带参数),分享到微信…...

图解RocketMQ之消息如何存储

大家好&#xff0c;我是苍何。 人一辈子最值得炫耀的不应该是你的财富有多少&#xff08;虽然这话说得有点违心&#xff0c;呵呵&#xff09;&#xff0c;而是你的学习能力。技术更新迭代的速度非常快&#xff0c;那作为程序员&#xff0c;我们就应该拥有一颗拥抱变化的心&…...

2024年中国信创产业发展白皮书精简版

获取方式&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEHMfcCfJm4A40vzrewoCw?pwda5u1 提取码&#xff1a;a5u1 得益于中国数字经济的迅猛发展&#xff0c;2023年中国信创产业规模达20961.9亿元&#xff0c;2027年有望达到37011.3亿元&#xff0c;中国信创市场…...

Redis2-Redis常见命令

目录 Redis数据结构介绍 Redis通用命令 KEYS DEL EXISTS EXPIRE String类型 Key的层级格式 Hash类型 List类型 Set类型 SortedSet类型 Redis数据结构介绍 Redis是一个key-value的数据库&#xff0c;key一般是String数据库&#xff0c;value的类型多种多样 可以通过…...

一天攻克一个知识点 —— 设计模式之动态代理

一、设计模式之代理设计 代理设计是在Java开发中使用较多的一种设计模式&#xff0c;所谓的代理设计模式就是指一个代理主体操作真实主体&#xff0c;真实主体操作具体业务&#xff0c;代理主体负责给具体业务添砖加瓦。 就好比在生活中你有一套房子想要出租(你真实主体)&…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...