【C++】vector 模拟实现
vector
- vector 容器
- vector 基本使用
- vector 定义
- 库中各类接口的使用
- 迭代器
- 容量相关接口
- 元素访问相关接口
- 元素修改相关接口
- 模拟实现 vector
- 前期准备
- 构造与析构
- 赋值运算符重载
- 迭代器相关
- 容量相关
- 元素访问相关
- 元素的修改相关
- 二维数组的创建
- 对于自定义类型数据的测试
vector 容器
C++ STL 中的 vector 就类似于 C 语言当中的数组,但是 vector 又拥有很多数组没有的接口,使用起来会更加的方便。
相比于 STL 中的 string ,vector 可以定义不同的数据类型
vector 基本使用
vector 定义
template < class T, class Alloc = allocator > class vector;
方式一:创建 vector 对象,不进行初始化
vector (const allocator_type& alloc = allocator_type());
方式二:创建 vector 对象,容量为 n,并赋值为 val
vector (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
方式三:创建 vector 对象,并采用区间赋值
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
方式四:拷贝构造
vector (const vector& x);
代码演示:
vector<int> v; //定义一个 int 类型变量vector<int> v0{ 1,2,3,4,5,6,7,8,9 }; //定义 int 数组并进行列表赋值PrintVector(v0);vector<int> v1(10, 5); //定义一个 int 类型数组,数组内容为 10 个 5PrintVector(v1);int arr[] = { 1,2,3,4,5,6 }; //区间构造vector<int> v2(arr, arr + sizeof(arr) / sizeof(arr[0]));PrintVector(v2);string s("hello"); //采用迭代器构造vector<char> v3(s.begin(), s.end());PrintVector(v3);vector<char> v4(v3); //拷贝构造PrintVector(v4);
定义一个打印函数可以很明显的观察到定义结果:
template<class T>
void PrintVector(const vector<T>& v)
{for (auto e : v)cout << e << " ";cout << endl;
}
库中各类接口的使用
迭代器
迭代器的本质是指针,其指针指向如下图:
begin() 指向空间起始位置,end() 指向最后一个有效元素的下一个位置
rbegin() 指向最后一个有效元素的下一个位置,rend() 指向空间的起始位置。
代码演示:
容量相关接口
代码演示:
(1)测试 size() 、capacity()、以及 resize()
vector<int> v{ 1,2,3,4,5,6 };PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;//resize 修改有效元素个数v.resize(10, 0); //将有效元素个数修改为 10,多余空间用 0 来进行填充PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.resize(20);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.resize(4); //有效元素个数缩小为 4PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;
可以发现:
resize 修改有效元素个数时,size 会进行相应的扩大或缩小变化,capacity 不一定会变化(有效元素增多时,若容量足够则capacity不变,否则会扩容;有效元素减少时,capacity 不变)
(2)测试 reserve
vector<int> v{ 1,2,3,4,5,6 };PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;//reserve 修改容量v.reserve(10);PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.reserve(30);PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;v.reserve(10);PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "----------------------------------------------------" << endl;
可以发现:
reserve 修改容量时,size 是不会发生变化的(因为有效元素个数不变),若空间容量扩大则 capacity 会相应的进行扩大,若空间容量缩小时 capacity 是不会发生变化的
(3)测试 empty
empty 是进行判空的接口
元素访问相关接口
(1)下标运算符访问 operator[]
越界测试:越界触发 assert 异常
(2)at 访问
越界测试:越界抛出 out_of_range 异常
(3)获取首尾元素 front back
元素修改相关接口
(1)尾插 push_back
(2)尾删 pop_back
(3)任意位置插入 insert
vector<int> v{ 1,2,3 };cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;v.insert(v.begin(), 100); //在起始位置插入 100PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;int arr[] = { 0,200,300,400 };v.insert(v.begin(), arr, arr + sizeof(arr) / sizeof(arr[0])); //起始位置插入arr数组中元素PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;v.insert(v.end(), 9); //尾部插入元素 9----------------同理也可以插入数组 arrPrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;v.insert(v.end(), arr, arr + sizeof(arr) / sizeof(arr[0])); //尾部插入arr数组中元素PrintVector(v);cout << "v.size() = " << v.size() << endl;cout << "v.capacity() = " << v.capacity() << endl;cout << "-----------------------------------------" << endl;
(4)任意位置删除 erase
(5)清空 clear
模拟实现 vector
前期准备
迭代器的本质就是指针,模拟实现 vector 容器,我们需要定义三个指针 :指向起始位置 start,指向最后一个有效元素的下一个位置 finish ,指向容器最后一个位置 endofstorage:
namespace xx { //自定义命名空间template<class T> //定义模板类型class vector{public:typedef T* iterator; //迭代器 等价于 T 类型指针private:iterator start; //空间起始位置iterator finish; //最后一个有效元素的下一个位置iterator endofstorage; //最后一个容量空间位置};
}
构造与析构
构造函数
(1)默认无参构造
vector() :start(nullptr), finish(nullptr), endofstorage(nullptr){}
(2)构造具有 n 个对象值为 val 的容器 (数据类型为模板类型 T)
vector(int n, const T& val = T()){start = new T[n]; //创建新空间for (size_t i = 0; i < n; ++i) {start[i] = val; //对空间进行赋值操作}finish = start + n; //修改 finish 指向---最后一个有效元素的下一个位置endofstorage = finish; //修改容量指针}
注意:
第二个参数 val 是一个缺省参数,对于内置类型,T() 的值为 0;对于自定义类型, T() 调用的是该自定义类型的默认构造函数
因此,对于自定义类型一定要有默认的构造函数,否则会报错
(3)使用迭代器进行构造
template<class Iterator>vector(Iterator first, Iterator last) //区间构造{auto it = first;size_t n = 0;while (it != last) {++it;n++; //统计区间中元素个数}start = new T[n]; //开辟空间finish = start;while (first != last) { //进行赋值*finish = *first;++first; ++finish;}endofstorage = finish; //修改容量指针}
(4)拷贝构造
vector(const vector<T>& v){size_t n = v.size(); //记录 v 中元素个数start = new T[n]; //创建新空间for (size_t i = 0; i < n; ++i){start[i] = v[i]; //进行赋值操作}finish = start + n; //修改指向endofstorage = finish;}
新写法(参考上一篇博客深浅拷贝问题)
vector(const vector<T>& v){vector<T> tmp(v.begin(),v.end()); //定义临时对象--调用迭代器构造方法this->swap(tmp); //进行资源交换}
析构函数
~vector(){if (start) {delete[] start;start = finish = endofstorage = nullptr;}}
测试代码
void MyvectorTest0()
{xx::vector<int> v1;xx::vector<int> v2(10, 5); int arr[] = { 1,2,3,4,5 }; //区间构造xx::vector<int> v3(arr, arr + sizeof(arr) / sizeof(arr[0]));xx::vector<int> v4(v2); //拷贝构造//遍历一:for (int i = 0; i < v2.size(); ++i) {cout << v2[i] << " ";}cout << endl;//遍历二:for (auto e : v3)cout << e << " ";cout << endl;//遍历三:auto it = v4.begin();while (it != v4.end()) {cout << *it << " ";++it;}cout << endl;}
会发现在运行代码时候出现的问题:
分析:
在构造 v2 时候,会调用区间构造方法,进行参数类型的推演,由于构造 v2 的两个参数都是 int 类型,故编译器会根据类型推演的结果来选择合适的构造方法,又因为构造 n 个值为 val 的构造方法中参数类型为 size_t , int,所以编译器认为类型不匹配,排除该构造方法,选用了迭代器区间的构造方法(参数类型实例化之后都为 int 类型),因此,为了实现构造 n 个值为 val 的空间构造,我们需要对构造函数进行一定的修改,使得其调用更准确:
赋值运算符重载
vector<T>& operator=(vector<T> v) { //因为参数是传值类型,故在传参过程中会进行一次拷贝构造的调用//赋值运算符重载this->swap(v); //直接进行交换(可以参考上一篇博客中深浅拷贝内容)return *this;}
迭代器相关
//迭代器iterator begin(){return start;}iterator end(){return finish;}
容量相关
(1)size、capacity、empty 的实现
size_t size()const {return finish - start;}size_t capacity()const {return endofstorage - start;}bool empty()const {return finish == start;}
(2)resize :修改有效元素个数
void resize(size_t newsize, const T&val = T()){size_t oldsize = size();if (newsize <= oldsize) { //缩小有效元素finish = start + newsize; //容量不变}else {//有效元素增大//需要扩容size_t cap = capacity();if(newsize > cap)reserve(newsize);for (size_t i = oldsize; i < newsize; ++i) {//多出来的空间填充start[i] = val;}finish = start + newsize;//endofstorage = finish;}}
(3)reserve:修改容量
void reserve(size_t newcapacity){size_t oldcapacity = capacity();if (newcapacity > oldcapacity) {//开辟新空间T* tmp = new T[newcapacity];if (start) {拷贝元素:memcpy(内存拷贝--------将一段空间中的内容原封不动的拷贝到新空间----浅拷贝) 按字节拷贝涉及到资源管理时,memcpy 属于浅拷贝//memcpy(tmp, start, sizeof(T)*size());for (size_t i = 0; i < size(); ++i) {tmp[i] = start[i];}//释放旧空间delete[] start;}size_t sz = size();start = tmp;finish = start + sz; //**********endofstorage = start + newcapacity;}}
代码测试:
(1)测试 resize (含 size, capacity 的测试)
(2)测试 reserve
元素访问相关
(1)获取首尾元素 front back
T& front(){return *start;}const T& front()const{return *start;}T& back(){return *(finish - 1);}const T& back()const{return *(finish - 1);}
(2)下标访问
T& operator[](size_t index){assert(index < size()); //注意区分异常处理方式return start[index];}const T& operator[](size_t index)const{assert(index < size());return start[index];}
(3)at 访问
T& at(size_t index){if (index >= size())throw out_of_range("vector at method: index out_of_range"); //抛出异常return start[index];}const T& at(size_t index)const{if (index >= size())throw out_of_range("vector at method: index out_of_range");return start[index];}
代码测试:
元素的修改相关
(1)尾插
void push_back(const T& val){//进行尾插,判断容量是否足够if (finish == endofstorage) {reserve(capacity() * 2 + 3); //按照2倍进行扩容}*finish = val;++finish;}
(2)尾删
void pop_back(){//进行尾删if (empty())return;--finish; //直接修改尾指针}
(3)任意位置插入
//insert 插入元素的时间复杂度 O(n)iterator insert(iterator pos, const T&val){//判断插入位置的合法性if (pos < begin() || pos > end())return end();//任意位置进行插入if (finish == endofstorage)reserve(capacity() * 2); //扩容auto it = finish - 1;while (it >= pos) { //元素后移*(it + 1) = *it;--it;}*it = val; //当前 it 指向的就是 pos 的位置++finish;return it; //返回新插入的元素的位置}
(4)任意位置删除
删除单个元素:
iterator erase(iterator pos){//删除任意位置元素if (empty())return end();if (pos < begin() || pos >= end())return end();//位置合理auto it = pos;while (it != end() - 1) //end() 表示最后一个有效元素的下一个位置{*it = *(it + 1); //元素前移--it;}--finish; //删除元素需要修改尾指针位置return pos;}
删除区间元素:
iterator erase(iterator start, iterator last){if (empty())return end();if (start < begin() || start >= end())return end();//位置合法, 删除区间auto beg = start;auto en = last;int n = last - start; //要删除的元素个数while (en != end()){*beg = *en;++beg; ++en;//--finish;}finish -= n;return start; //返回删除的区间首元素位置}
(5)清空
void clear(){erase(begin(), end());}
(6)交换函数
void swap(vector<T>& v){std::swap(start, v.start);std::swap(finish, v.finish);std::swap(endofstorage, v.endofstorage);}
测试代码:
(1)测试尾插尾删:
(2)测试任意位置的插入删除:
(3)清空:
二维数组的创建
创建一个五行六列数组,数组中元素值都为 8:
void MyvectorTest3()
{xx::vector<xx::vector<int>> vv(5, xx::vector<int>(6, 8)); //创建有 5 个元素的数组,数组中元素用 vector<int>(6,8) 来进行填充for (size_t i = 0; i < vv.size(); ++i){for (size_t j = 0; j < vv[i].size(); ++j)cout << vv[i][j] << " ";cout << endl;}
}
对于自定义类型数据的测试
上述的测试我们都是基于内置类型int数据的测试,发现代码可以正确运行没有报错,那针对于自定义类型数据是否正确呢?
(1)定义一个日期类:
class Date {
public:Date(int year = 1990, int month = 1, int day = 20){_year = year;_month = month;_day = day;}Date(const Date& d){//拷贝构造_year = d._year;_month = d._month;_day = d._day;}~Date() {}
private:int _year;int _month;int _day;
};void MyvectorTest4()
{xx::vector<Date> d; //定义 Date 类型数组d.push_back(Date(2023, 1, 1)); //插入元素--------Date 构造函数必须为带缺省值的构造方法d.push_back(Date(2023, 1, 2));d.push_back(Date(2023, 1, 3));d.push_back(Date(2023, 1, 4));d.push_back(Date(2023, 1, 5));cout << d.size() << endl;
}
运行改代码显式可以正确运行,因为 Date 类不存在资源的处理,那针对于 string 类是否正常?
我们来试试:
(2)定义 string 类:
class String {
public:String(const char* str=""):_str(nullptr){//构造if (nullptr == str)str = "";_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s):_str(new char[strlen(s._str)+1]){//拷贝构造strcpy(_str, s._str);}String& operator=(const String& s){if (this != &s) {//不是给自己的赋值char* tmp = new char[strlen(s._str) + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;}return *this;}//String& operator=(const String s)//{// if (this != &s) {// //新写法// this->swap(s._str);// }// return *this;//}~String(){if (_str) {delete[] _str;_str = nullptr;}}
private:char* _str;
};void MyvectorTest5()
{xx::vector<String> s;s.push_back("hello");s.push_back("welcom");s.push_back("come on");cout << s.size() << endl;s.push_back("hahahha"); //此时需要进行扩容发生报错----------memcpy是属于浅拷贝}
运行发现,在最后一次尾插时发生了错误,我们来看看是什么原因导致的:
因为在第四次尾插时候需要进行扩容,因此产生了错误
往下运行一步就会发现问题所在了:
发现,在进行 memcpy 拷贝时候发生了浅拷贝,即将原空间内容原封不动的拷贝到新空间,这就导致了新空间共享旧空间的地址,会造成内存泄漏
因此,在扩容时候我们需要按元素将旧空间中元素交给新空间,而不是将地址空间也赋给新空间
进行修改:
修改之后程序可以正常运行。
_CrtDumpMemoryLeaks(); //检测内存泄漏
该章节完整代码:
添加链接描述
本篇内容就分享到这里啦!!!
学习编程的道路很长,要注重自我实践与验证,欢迎读者评论探讨~
相关文章:

【C++】vector 模拟实现
vectorvector 容器vector 基本使用vector 定义库中各类接口的使用迭代器容量相关接口元素访问相关接口元素修改相关接口模拟实现 vector前期准备构造与析构赋值运算符重载迭代器相关容量相关元素访问相关元素的修改相关二维数组的创建对于自定义类型数据的测试vector 容器 C S…...

canvas初体验
canvas介绍 Canvas 最初由Apple于2004 年引入,用于Mac OS X WebKit组件,为仪表板小部件和Safari浏览器等应用程序提供支持。后来,它被Gecko内核的浏览器(尤其是Mozilla Firefox),Opera和Chrome实现&#x…...

JavaWeb12-线程通讯(线程等待和唤醒)
目录 1.方法介绍 1.1.wait()/wait(long timeout):让当前线程进入等待状态。 1.1.1.wait执行流程 1.1.2.wait结束等待的条件 1.1.3.wait() VS wait(long timeout) 1.1.4.为什么wait要放在Object中? --->PS:wait(0) 和 sleep(0) 的区…...

江苏专转本如何事半功倍的备考
专转本如何事半功倍的备考 一个人学习成绩的优劣取决于他的学习能力,学习能力包括三个要素:规范的学习行为;良好的学习习惯;有效的学习方法。有了规范的学习行为才能培养出良好的学习习惯,形成了良好的学习习惯就会形成…...

linux下安装mongoDB
一、下载mongoDB包 下载地址: https://www.mongodb.com/try/download/community 个人建议:如果是学习阶段,使用5以下版本更好些。 二、安装及配置 1、安装 # 1、解压 $ tar -zxvf mongodb-linux-x86_64-rhel70-4.4.19-rc1.tgz# 2、迁移目…...

掌握MySQL分库分表(七)广播表、绑定表实战,水平分库+分表实现及之后的查询和删除操作
文章目录什么是广播表广播表实战数据库配置表Java配置实体类配置文件测试广播表水平分库分表配置文件运行测试什么是绑定表?绑定表实战配置数据库配置Java实体类配置文件运行测试水平分库分表后的查询和删除操作查询操作什么是广播表 指所有的分片数据源中都存在的…...

企业为什么需要数据可视化报表
数据可视化报表是在商业环境、市场环境已经改变之后,发展出来为当前企业提供替代解决办法的重要方案。而且信息化、数字化时代,很多企业已经进行了初步的信息化建设,沉淀了大量业务数据,这些数据作为企业的资产,是需要…...

5个有效的华为(HUAWEI)手机数据恢复方法
5个有效的手机数据恢复方法 华为智能手机中的数据丢失比许多人认为的更为普遍。发生这种类型的丢失有多种不同的原因,因此数据恢复软件的重要性。您永远不知道您的智能手机何时会在这方面垮台;因此,预防总比哀叹好,这就是为什么众…...

【Java并发编程】线程安全(一)Synchronized原理
Synchronized底层实现 简单来说,Synchronized关键字的执行主体是线程对象,加锁是通过一个锁对象来完成的是,而锁对象底层关联了一个c源码的monitor的对象,monitor对象底层又对应了操作系统级别的互斥锁,同一时刻只有一…...

[apollo]vue3.x中apollo的使用
[apollo]vue3.x中apollo的使用通过客户端获取Apollo配置环境工具的安装获取Apollo配置相关代码错误提示Uncaught (in promise) Error: Apollo client with id default not found. Use provideApolloClient() if you are outside of a component setup通过开放接口获取Apollo配置…...

system()函数启用新进程占有原进程的文件描述符表的问题
我在A程序中占用了/dev/video0这个独占模式的设备文件,在A中用system函数启用了B程序,B程序的代码中并不包含对/dev/video0的访问,但是我发现B程序也占用了/dev/video0,并且我在A程序中关闭了/dev/video0后,A程序不再占…...

nignx(安装,正反代理,安装tomcat设置反向代理,ip透传)
1安装nginx 安装wget Yum install -y wget 下载(链接从官网找到右键获取) 以下过程root 安装gcc Yum -y install gcc c 安装pcre Yum install -y pcre pcre-devel Openssl Yum install -y openssl openssl-devel 安装zlib Yum install -y zlib zlib-devel 安装make Yum inst…...

sklearn模块常用内容解析笔记
文章目录 回归模型评价指标R2_score预备知识R2_score计算公式r2_score使用方法注意事项参考文献回归模型评价指标R2_score 回归模型的性能的评价指标主要有:RMSE(平方根误差)、MAE(平均绝对误差)、MSE(平均平方误差)、R2_score。但是当量纲不同时,RMSE、MAE、MSE难以衡量模…...

我的 System Verilog 学习记录(2)
引言 从本文开始,就开始系统学习 System Verilog ,不只是语法,还有结合 Questa Sim 的实际编程练习、Debug。 本文简单介绍 System Verilog 语言的用途以及学习的必要性。 前文链接: 我的 System Verilog 学习记录(…...

【调研报告】Monorepo 和 Multirepo 的风格对比及使用示例
带有权重的Monorepo和Multirepo对比 功能/特性MonorepoMultirepoMonorepo权重值Multirepo权重值代码管理管理多个代码库更加复杂管理单个代码库更加简单37依赖管理可以简化依赖管理依赖冲突可能会更加困难73构建和部署构建和部署更加容易构建和部署可能需要更多的配置82团队协…...

Retrofit源码分析
文章目录一、简介二、源码分析2.1Retrofit的本质流程2.2源码分析2.2.1 创建Retrofit实例步骤1步骤2步骤3步骤4步骤5总结2.2.2创建网络请求接口的实例外观模式 & 代理模式1.外观模式2. 代理模式步骤3步骤4总结2.2.3执行网络请求同步请求OkHttpCall.execute()1.发送请求过程2…...

Mybatis-Plus入门系列(20) -兼容多种数据库
有道无术,术尚可求,有术无道,止于术。 文章目录前言方案分析1. 分页2. XML自定义SQL案例演示1. 配置2. 简单分页查询3. 带方言的分页查询参考前言 在我们实际开发软件产品过程中,数据库的类型可能不是确定的,也有客户…...

JetPack板块—Android X解析
Android Jetpack简述 AndroidX 是Android团队用于在Jetpack中开发,测试,打包,发布和版本管理的开源项目。相比于原来的Android Support库,AndroidX 可以称得上是一次重大的升级改进。 和Support库一样,AndroidX与Android 操作系…...

C++学习笔记-数字
当我们使用数字时,通常我们使用原始数据类型,例如 int,short,long,float 和 double 等。数字数据类型,它们的可能值和取值范围在讨论 C 数据类型时已经解释了。 C 定义数字 我们已经在之前笔记的各种实例…...

Nginx——Nginx的基础原理
摘要 Nginx 是俄罗斯人编写的十分轻量级的 HTTP 服务器,是一个高性能的HTTP和反向代理服务器,同时也是一个 IMAP/POP3/SMTP 代理服务器。Nginx 是由俄罗斯人 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,它已经在该站点运行超过两年半了。…...

服务端开发Java之备战秋招面试篇1
在这个面试造火箭工作拧螺丝的时代背景下,感觉不是很好,不过还好也是拿到了还行的offer,准备去实习了,接下来就是边实习边准备秋招了,这半年把(技术栈八股文面经算法题项目)吃透,希望…...

【C++的OpenCV】第三课-OpenCV图像加载和显示
我们开始学习OpenCV一、OpenCV加载图片和显示图片1.1 imread()函数的介绍1.2 cv::namedWindow()函数的介绍1.4 imshow()函数介绍1.5 Mat容器介绍二、 代码实例(带注释)2.1 代码2.2 执行结果一、OpenCV加载图片和显示图片 本章节中,将会学习到…...

【面试1v1实景模拟】Spring事务 一文到底
老面👴:小伙子,了解Spring的事务吗? 解读🔔:这个必须了解,不了解直接挂~😂😂😂,但面试官肯定不是想听你了解两个字,他是想让你简单的介绍下。 笑小枫🍁:了解,事务在逻辑上是一组操作,要么执行,要不都不执行。主要是针对数据库而言的,比如说 MySQL。为…...

Neuron Selectivity Transfer 原理与代码解析
paper:Like What You Like: Knowledge Distill via Neuron Selectivity Transfercode:https://github.com/megvii-research/mdistiller/blob/master/mdistiller/distillers/NST.py本文的创新点本文探索了一种新型的知识 - 神经元的选择性知识,…...

vue项目关闭子页面,并更新父页面的数据
今天下午是一个非常痛苦的,想要实现一个功能: 父页面打开了一个新的页面(浏览器打开一个新的窗口),并在子页面提交数据之后,父页面的数据要同步更新。 难点:父页面是一个表格列表,…...

第五次作业:修改redis的配置文件使得windows的图形界面客户端可以连接redis服务器
1. 安装 Redis 依赖 Redis 是基于 C语言编写的,因此首先需要安装 Redis 所需要的 gcc 依赖: yum install -y gcc tcl 2、上传安装文件 将下载好的 redis-6.2.7.tar.gz 安装包上传到虚拟机的任意目录(一般推荐上传到 /usr/local/src目录&am…...

【11】FreeRTOS的延时函数
目录1.延时函数-介绍2.相对延时函数-解析2.1函数prvAddCurrentTaskToDelayedList-解析2.3滴答定时器中断服务函数xPortSysTickHandler()-解析2.4函数taskSWITCH_DELAYED_LISTS() -解析3.延时函数-实验4.总结1.延时函数-介绍 函数描述vTaskDelay()相对延时xTaskDelayUntil()绝对…...

Vue页面组成及常用属性
一、Vue页面组成 目前的项目中,Vue页面都是采用组件套娃的形式,由一个一个的组件拼接而成整个页面。一个组件就是一个.vue文件。组件通常由template和script两部分组成: template部分:页面展示的具体元素内容,比如文字…...

j6-IO流泛型集合多线程注解反射Socket
IO流 1 JDK API的使用 2 io简介 输入流用来读取in 输出流用来写出Out 在Java中,根据处理的数据单位不同,分为字节流和字符流 继承结构 java.io包: File 字节流:针对二进制文件 InputStream --FileInputStream --BufferedInputStre…...

创业能否成功?这几个因素很重要!
创业能否成功?这几个因素很重要! 2023-02-22 19:06:53 大家好,我是你们熟悉而又陌生的好朋友梦龙,一个创业期的年轻人 上周末跟朋友一起钓鱼,他跟吐槽现在生意越来越难做。他是我身边可以说是创业很成功的例子&#…...