C++11(中)
C++11(中)
- 1.可变参数模板
- 1.1.使用场景
- 2.lambda表达式(重要)
- 2.1.使用说明
- 2.2.函数对象与lambda表达式
- 3.线程库
- 3.1.thread
- 3.2.atomic原子库操作
- 3.3.mutex
- 3.3.1.mutex的种类
- 3.3.2.lock_guard
- 3.3.3.unique_lock
🌟🌟hello,各位读者大大们你们好呀🌟🌟
🚀🚀系列专栏:【C++的学习】
📝📝本篇内容:可变参数模板;可变参数使用场景;lambda表达式;lambda表达式使用说明;函数对象与lambda表达式;线程库;thread;atomic原子库操作;mutex;mutex的种类;lock_guard;unique_lock
⬆⬆⬆⬆上一篇:C++11(上)
💖💖作者简介:轩情吖,请多多指教(> •̀֊•́ ) ̖́-
1.可变参数模板
C++11的新特性可变参数模板能够让我们创建可以接受可变参数的函数模板和类模板
#include <iostream>
using namespace std;
template<class ...Args>
void ShowList(Args ...args)
{
//Args是一个模板参数包,args是一个函数形参参数包
//声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数
}
int main()
{ShowList();return 0;
}
上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点
下面举一个栗子
#include <iostream>
using namespace std;
void ShowList()
{
//递归终止函数
}
template<class T,class ...Args>
void ShowList(T value,Args... args)
{cout << value << endl;
//Args是一个模板参数包,args是一个函数形参参数包
//声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数ShowList(args...);
}
int main()
{ShowList(1,2,3,4,5,6,7,8,9,10);return 0;
}
还可以使用逗号表达式来展开参数包
#include <iostream>
#include <string>
using namespace std;
template<class T>
void Print(T value)
{cout << value << endl;
}
template<class ...Args>
void ShowList(Args... args)
{int arr[] = {(Print(args),0)...};
}
int main()
{ShowList(1,string("hello world"),3, 4.1, 5, 6, 7, 8, 9, 10);return 0;
}
我们的的数组元素其实会初始化,{(Print(args), 0)…}将会展开成((Print(arg1),0),(Print(arg2),0),(Print(arg3),0), etc… ),在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包
1.1.使用场景
在我们的很多STL容器中,也使用到了可变参数模板
上面两个就是最简单的例子,我们可以看到emplace_back函数就是使用了可变参数包,同时他还是万能引用
那它和我们的push_back有啥区别呢?
让我们来看一下它的底层先,我们在VS2022下演示
我们选中emplace_back,然后按下F12,此时会跳转到下图
此时再跳转到_Emplace_one_at_back
此时再进行跳转到_Emplace_reallocate
我们可以看见construct,继续跳转
到底了,无法再继续跳转了,其实它的底层就是使用了定位new,如果是不知道什么是定位new可以看一下我这篇博客☞C++内存管理
不知道大家有没有看过我们侯捷大佬的《STL源码剖析》,在这本书的第二章的空间配置器中就讲到了construct的底层,我可以给大家看一下,具体的编译器和具体的版本实现会不一样,但是大差不差
接下来我们回归主题,来研究一下,emplace_back有啥区别,我们首先用到我们自己模拟实现的string
#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <cassert>
using namespace std;
namespace lnb
{class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _arr;}iterator end(){return _arr + _size;}const iterator begin()const{return _arr;}const iterator end()const{return _arr + _size;}string(const char* str = ""):_size(strlen(str)), _capacity(_size){cout << "string(const char* str)" << endl;if (_size == 0){_capacity = 4;}_arr = new char[_capacity+1];strcpy(_arr, str);}string(const string& str){cout << "string(const string& str)——深拷贝" << endl;_arr = new char[str._capacity + 1];strcpy(_arr, str._arr);_size = str._size;_capacity = str._capacity;}string(string&& str):_arr(nullptr),_size(0),_capacity(0){cout << "string(const string&& str)——移动拷贝" << endl;swap(str);//这边之所以可以传递到左值引用,是因为当实参传给str后,有了左值的属性}const string& operator=(const string& str){cout << "const string& operator=(const string& str)—赋值重载" << endl;if (this != &str){char* tmp = new char[str._capacity + 1];delete[] _arr;_arr = tmp;strcpy(_arr, str._arr);_capacity = str._capacity;_size = str._size;}return *this;}const string& operator=(string&& str){cout << "const string& operator=(string&& str)——移动赋值" << endl;swap(str);return *this;}~string(){delete[] _arr;_size = _capacity = 0;}const char* c_str(void){return _arr;}size_t size()const{return _size;}size_t capacity()const{return _capacity;}char& operator[](size_t pos){assert(pos < _size);return _arr[pos];}char& operator[](size_t pos)const{assert(pos < _size);return _arr[pos];}void Print(const string& str){for (size_t i = 0; i < str._size; i++){cout << str[i] << " ";}cout << endl;iterator bg = str.begin();while (bg != str.end()){cout << *bg << endl;bg++;}}void reserve(size_t size){char* tmp = new char[size + 1];strcpy(tmp, _arr);delete _arr;_arr = tmp;_capacity = size;}void resize(size_t size, char c = '\0'){if (size <= _size){_arr[size] = '\0';_size = size;}else{if (size > _capacity){reserve(size);}size_t i = _size;while (i < size){_arr[i] = c;i++;}_size = size;_arr[_size] = '\0';}}void swap(string& str){std::swap(_arr, str._arr);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}private:char* _arr;size_t _size;size_t _capacity;static const size_t npos = -1;};
}
class Date
{
public:Date(int year,int month,int day):_year(year),_month(month),_day(day){cout << "Date(int year,int month,int day)" << endl;}Date(Date&& d){cout << "Date(Date&& d)——移动拷贝" << endl;}Date(const Date& d){cout << "Date(const Date& d)——拷贝构造函数" << endl;}private:int _year;int _month;int _day;
};
int main()
{/*list<lnb::string> mylist;mylist.push_back("1111");cout << "----------------------" << endl;mylist.emplace_back("1111");*//*list<Date> mylist;mylist.push_back({ 2024,11,18 });cout << "----------------------" << endl;mylist.emplace_back( 2024,11,18);*//*lnb::string str("hello world");vector<Date> myvector;myvector.push_back({2024,11,18});cout << "----------------------" << endl;myvector.emplace_back(2024,11,18);*//*list<pair<int,lnb::string>> mylist;mylist.push_back(make_pair(10,lnb::string("1111")));cout << "-------------------------------" << endl;mylist.emplace_back(1,lnb::string("1111"));*/return 0;
}
其实emplace_back依靠的是定位new的调用,实际效率差不多,可以无脑使用emplace
2.lambda表达式(重要)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Goods
{string _name;// 名字double _price;// 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};
struct ComparePriceLess
{bool operator()(const Goods& gl, const Goods& gr){return gl._price < gr._price;}
};
struct ComparePriceGreater
{bool operator()(const Goods& gl, const Goods& gr){return gl._price > gr._price;}
};
int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater());return 0;
}
每当我们需要使用各种算法时就会需要用到仿函数,但是次数一旦多了就会比较复杂和不便,因此出现了lambda表达式
2.1.使用说明
格式说明:
lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement}
①lambda表达式各部分说明
[capture-list]:捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[ ]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用
(parameters):参数列表,与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略
mutable:默认情况下,lambda函数总是const函数,不能对其捕获的参数进行修改,mutable可以取消其常量性。使用该修饰符时,参数列表不能省略(即使参数为空)
->returntype:返回值类型,用追踪返回类型形式声明函数的返回值类型,没有返回值可以省略。返回值类型明确的情况下也可以省略,由编译器对返回类型进行推导
{}:函数体,在函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量
最简单的lambda函数:[]{}
②捕获列表说明
[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕获变量var
[&]:表示引用传递捕获所有父作用域中的变量(包括this)
[this]:b表示值传递方式捕获当前的this指针
注意:
① 在块作用域以外的lambda函数捕捉列表必须为空
②语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:
[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量
[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
③捕捉列表不允许变量重复传递,否则就会导致编译错误。
比如:
[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复
看接下来的栗子
#include <iostream>
using namespace std;
struct Date
{
public:Date(int year,int month,int day):_year(year),_month(month),_day(day){}Date(const Date& d){//for example 3[this,&d] {_year = d._year;_month = d._month;_day = d._day;}();}int _year;int _month;int _day;
};
int main()
{int out = 10;{//for example 1cout << "for example 1:";int x = 10;int y = 20;auto f1 = [=]()->int{return x + y; };//具体用什么类型接受后续会讲cout<<f1() << endl;//for example 2cout << "for example 2:";[=](int a, int b)mutable{a = 10;b = 20;//不使用mutable可以修改x = 11;//不使用mutable无法修改out = 10;//也可以捕获cout << "a=" << a << ",b=" << b << ",x=" << x << ",out=" << out << endl;}(100,200);//for example 3cout << "for example 3:";Date d1(2024, 11, 18);Date d2(d1);cout << d2._year << ":" << d2._month << ":" << d2._day << endl;}return 0;
}
#include <iostream>
using namespace std;
int main()
{auto f1=[]() {return 1; };auto f2(f1);//可以拷贝构造//f1 = f2;//不能进行相互赋值int(*fptr)(void) = f1;//可以赋值给相同类型的函数指针return 0;
}
可以看出lambda表达式实际是一个匿名函数
2.2.函数对象与lambda表达式
#include <iostream>
using namespace std;
struct Add
{int operator()(int x,int y){return x + y;}
};
int main()
{Add x;cout<<x(1, 2)<<endl;//3auto y= [](int x, int y) {return x + y; };cout<<y(1, 2)<<endl;//3return 0;
}
从使用方式上来看,函数对象与lambda表达式完全一样
实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。
如果在VS2019中的话,类的名称是lambda_uuid,但是在VS2022下就不是了,对于什么是uuid,简单来说就是通用唯一标识符 (UUID) 是一种特定形式的标识符,在大多数实际用途中可以安全地认为是唯一的。两个正确生成的 UUID 相同的可能性几乎可以忽略不计,即使它们是由不同的各方在两个不同的环境中创建的。
3.线程库
3.1.thread
现在C++11支持多线程了,以前的话会因为平台的的接口问题,导致移植性较差,现在就可以完全解决这个问题了
☞thread文档
我们首先来看一下thread类的基本使用以及常用的调用接口
首先是构造函数
如果构造函数不带任何参数,没有提供线程函数,该对象实际没有任何线程,没什么用处
在上面的代码中还用到了get_id()成员函数,它其实是一个std下封装的一个类,返回值为id类型
接下来,我们提供一下线程函数,来正式使用一下线程
线程函数一般有三种方式提供,分别是lambda表达式,函数对象,函数指针
#include <iostream>
#include <thread>
#include <future>
using namespace std;
void Func(int x,int y)
{cout << "x:" << x << ",y:" << y << endl;cout << "I am thread t2" << endl;
}struct Add
{int operator()(int x, int y){cout << "I am thread t3" << endl;return x + y;}
};int main()
{//for example 1-lambda表达式作为线程函数thread t1([]() {cout << "I am thread t1" << endl;});//for example 2-函数指针作为线程函数int a = 10;int b = 20;thread t2(&Func,a,b);//for example 3-函数对象作为线程函数thread t3(Add(), a, b);t1.join();//等待线程t2.join();t3.join();future<int> result = async(Add(),a,b);//获取线程的返回值cout <<"thread t3 return->"<<result.get() << endl;cout << "Main thread" << endl;return 0;
}
顺序看着比较乱,这是因为线程都是在同时进行的,没有进行同步互斥操作,并且我们代码最后需要等待线程,使用join,不然线程还没执行完,主线程就结束了
我们的thread是防拷贝的,不允许拷贝构造和赋值重载,但是可以移动构造和移动赋值,即将一个线程的状态转给其他线程对象,转移期间不影响线程的执行
#include <iostream>
#include <thread>
#include <Windows.h>
using namespace std;
int main()
{//模仿线程池thread thread_array[5];for (int i=0;i<sizeof(thread_array)/sizeof(thread_array[0]);i++){thread_array[i] = thread([i]()//移动赋值重载{printf("I am thread t%d\n", i+1);});}for (int i = 0; i < 5; i++){thread_array[i].join();}return 0;
}
我们可以通过joinable,来判断线程是否有效,对于一下任意情况,线程无效:
①采用无参构造函数构造的线程对象
②线程对象的状态已经转移给其他线程对象
③线程已经调用jionable或者detach结束
其中第三点可能不太理解detach,我们来演示一下,它其实就是不需要主线程等待了
#include <iostream>
#include <thread>
#include <Windows.h>
using namespace std;
void Func(int& x)
{while (1){cout << "thread 1,x="<<x<< endl;Sleep(1000);}
}int main()
{int a = 10;thread t1(Func,ref(a));//传引用就得用reft1.detach();//使用后主线程就不需要再等待了Sleep(10000);return 0;
}
在上面图中演示了detach的使用,同时还有一个关注点,就是如果线程函数的参数要使用引用,得需要使用ref(),也可以使用指针来改变对应的值,我们一般线程函数的参数是以值拷贝的方式拷贝到线程栈空间中的
#include <iostream>
#include <thread>
using namespace std;
struct Date
{void print(){cout << _year << "/" << _month << "/" << _day << endl;}int _year=2024;int _month=11;int _day=19;
};
int main()
{Date d;thread t1(&Date::print,&d);//类成员函数作为线程函数时需要带上thist1.join();return 0;
}
3.2.atomic原子库操作
在我们日常使用多线程中最担心的就是碰到线程安全问题,因此我们C++11就有了原子操作库,
对于原子操作,简单来说就是一个事件只有两种情况,要么做完,要么没做,因此使用后原子操作库后就能保证安全
☞atomic原子库文档
原子类型只能从其模板参数中进行构造,不允许拷贝构造,移动构造以及赋值重载等,为了防止意外,标准库已经将atmoic模板类中的拷贝构造、移动构造、赋值重载等。
符重载默认删除掉了。
#include <iostream>
#include <thread>
using namespace std;
int num = 0;
void Func()
{int i = 100;while(i--)num++;
}int main()
{thread t1(Func);thread t2(Func);t1.join();t2.join();cout << num << endl;return 0;
}
上图中的内容为没有使用原子打印出的结果,我们的理想结果为200,但是结果显而易见,不过在多次尝试中,也很多次的达到了200,但这样是有线程安全问题的
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
atomic<int> num=0;//使用原子操作
void Func()
{int i = 100;while(i--)num++;
}int main()
{thread t1(Func);thread t2(Func);t1.join();t2.join();cout << num.load() << endl;return 0;
}
如上代码就没问题了,我们如果需要知道num原本的类型值,就可以使用load成员函数,有的同学可能会考虑到使用锁,确实没问题,我们后面就会讲解,但是对于使用锁的话,效率比较低,而且锁一不注意就会造成死锁,而我们的原子操作可以保证高效率和安全。
3.3.mutex
3.3.1.mutex的种类
所有的锁对象之间不能进行拷贝,也不能进行移动赋值
C++11一共提供4种锁,分别是mutex,recursive_mutex,timed_mutex,recursive_timed_mutex
①mutex:
mutux是最常用的锁了,它常用的函数有:lock(),unlock(),try_lock()
lock()可能会发生的情况:
如果该锁没有被别的线程获取,则获取这个锁,直到unlock前,一直获得这个锁
如果当前锁被其他线程已经获取,那么调用线程就阻塞
如果当前锁被其他线程获取不释放,而当前线程又获取了其他线程所需要的锁,那么就会造成死锁
try_lock()可能会发生的情况:
- 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量
- 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉
- 如果当前互斥量被当前调用线程锁住,则会产生死锁
②recursive_mutex:
这个锁允许同一个线程对锁多次上锁(递归上锁),来获得对锁对象的多层所有权,释放锁时需要调用与该锁层次深度相同的unlock
其余两个就不多赘述了,可以查文档
③timed_mutex:timed_mutex文档
④recursive_timed_mutex:recursive_timed_mutex文档
3.3.2.lock_guard
在我们使用锁的过程中,难免会遇到忘记解锁,因此出现了lock_guard类模板,它主要是通过RAII的方式,对其管理的锁进行了封装,在需要加锁的地方,只需要用上述介绍的任意锁实例化一个lock_guard,调用构造函数成功上锁,出作用域前,lock_guard对象要被销毁,调用析构函数自动解锁
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
using namespace std;
int num=0;
mutex _m;
void Func()
{int i = 100;lock_guard<mutex> guard(_m);//使用while(i--)num++;
}int main()
{thread t1(Func);thread t2(Func);t1.join();t2.join();cout << num<< endl;return 0;
}
上面为使用了库中的lock_guard,其实它的写法很简单,我自己也写了一lock_guard模拟实现
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
using namespace std;
namespace lnb
{template<class M>class lock_guard//模拟实现{public:lock_guard(M& m):_m(m){_m.lock();}~lock_guard(){_m.unlock();}private:M& _m;};
}int num=0;
mutex mtx;
void Func()
{int i = 100;lnb::lock_guard<mutex> guard(mtx);//使用while(i--)num++;
}int main()
{thread t1(Func);thread t2(Func);t1.join();t2.join();cout << num<< endl;return 0;
}
3.3.3.unique_lock
与lock_gard类似,unique_lock类模板也是采用RAII的方式对锁进行了封装,并且也是以独占所有权的方式管理mutex对象的上锁和解锁操作,即其对象之间不能发生拷贝。在构造(或移动(move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作,与lock_guard不同的是,unique_lock更加的灵活,提供了更多的成员函数
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
using namespace std;
int num=0;
mutex mtx;
void Func()
{int i = 100;unique_lock<mutex> uq(mtx);//使用while(i--)num++;
}int main()
{thread t1(Func);thread t2(Func);t1.join();t2.join();cout << num<< endl;return 0;
}
🌸🌸C++11(中)的知识大概就讲到这里啦,博主后续会继续更新更多C++的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪
相关文章:
C++11(中)
C11(中) 1.可变参数模板1.1.使用场景 2.lambda表达式(重要)2.1.使用说明2.2.函数对象与lambda表达式 3.线程库3.1.thread3.2.atomic原子库操作3.3.mutex3.3.1.mutex的种类3.3.2.lock_guard3.3.3.unique_lock 🌟&#x…...
vim 如何高亮/取消高亮
高亮 :在ESC模式下使用 shift # 取消高亮:在ESC模式下输入英文输入 :nohl (no highlight)...
C#中面试的常见问题008
1.内存泄露 内存泄露的原因: 未释放动态分配的内存:在使用malloc、new等动态内存分配函数后,未能正确释放内存。引用计数错误:在引用计数管理内存的语言中,增加引用计数但未相应减少,导致内存无法释放。循…...
【系统架构设计师】真题论文: 论数据访问层设计技术及其应用(包括解题思路和素材)
更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 真题题目(2016年 试题3)解题思路论文素材参考(1)数据访问层设计 JDBC 技术(2)ORM 框架技术 - Hibernate(3)ORM 框架技术 - MyBatis(4)数据访问层设计模式 - DAO 模式(5)数据访问层设计模式 - Repositor…...
力扣整理版九:贪心算法(待整理)
局部最优 全局最优 局部最优可以推出全局最优 并且想不出反例 ----------------------------- (1) 455 分发饼干 (2) 1005 k次取反后最大化的数组和 (3) 860 柠檬水找零 (2) 376 摆动序列 (3) 122 买卖股票的最佳时机2 (4) 135 分发糖果 (4) 55 跳跃游戏 (5) 45 跳…...
香橙派--安装RKMPP、x264、libdrm、FFmpeg(支持rkmpp)以及opencv(支持带rkmpp的ffmpeg)(适用于RK3588平台)
1. 安装RKMPP git clone https://github.com/rockchip-linux/mppcd mpp/build/linux/aarch64./make-Makefiles.bashmake -j8sudo make installRKMPP:用于编解码测试,支持RK3588平台。 2. 安装x264 git clone https://code.videolan.org/videolan/x264…...
计算机毕业设计Python+大模型美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
1138:将字符串中的小写字母转换成大写字母
【题目描述】 给定一个字符串,将其中所有的小写字母转换成大写字母。 【输入】 输入一行,包含一个字符串(长度不超过100,可能包含空格)。 【输出】 输出转换后的字符串。 【输入样例】 helloworld123Ha 【输出样例】…...
Wireshark抓取HTTPS流量技巧
一、工具准备 首先安装wireshark工具,官方链接:Wireshark Go Deep 二、环境变量配置 TLS 加密的核心是会话密钥。这些密钥由客户端和服务器协商生成,用于对通信流量进行对称加密。如果能通过 SSL/TLS 日志文件(例如包含密钥的…...
Unity UGUI原理剖析
UI最重要的两部分 UI是如何渲染出来的点击事件如何触发何时发生UI重绘 1:UI如何渲染出来的 UI渲染一定是有顶点的,没有顶点就没法确定贴图的采样,UGUI的顶点在一张Mesh上创建,经过渲染管线UI就渲染到屏幕上了,UI的渲染…...
实现Excel文件和其他文件导出为压缩包,并导入
导出 后端: PostMapping("/exportExcelData")public void exportExcelData(HttpServletRequest request, HttpServletResponse response, RequestBody ResData resData) throws IOException {List<Long> menuIds resData.getMenuIds();List<Co…...
Linux:基础开发工具
目录 软件包管理器yum 什么是软件包? 查看软件包 安装软件 卸载软件 vim vim的基本操作 gcc/g使用 预处理 编译 汇编 连接 make/Makefile .PHONY伪目标 定义使用变量 版本控制器Git 安装git git的使用 git add git commit git push git pull …...
【mac】终端左边太长处理,自定义显示名称(terminal路径显示特别长)
1、打开终端 2、步骤 (1)修改~/.zshrc文件 nano ~/.zshrc(2)添加或修改PS1,我是自定义了名字为“macminiPro” export PS1"macminiPro$ "(3)使用 nano: Ctrl o (字母…...
嵌入式硬件设计:从概念到实现的全流程
嵌入式硬件设计是现代电子技术中一个至关重要的领域,涉及从硬件架构设计到硬件调试的各个方面。它为我们日常生活中的各类智能设备、家电、工业控制系统等提供了强大的支持。本文将介绍嵌入式硬件设计的基本流程、关键技术、常用工具以及常见的挑战和解决方案&#…...
【Nginx】核心概念与安装配置解释
文章目录 1. 概述2. 核心概念2.1.Http服务器2.2.反向代理2.3. 负载均衡 3. 安装与配置3.1.安装3.2.配置文件解释3.2.1.全局配置块3.2.2.HTTP 配置块3.2.3.Server 块3.2.4.Location 块3.2.5.upstream3.2.6. mine.type文件 3.3.多虚拟主机配置 4. 总结 1. 概述 Nginx是我们常用的…...
数据库-MySQL-MybatisPlus实战
文章目录 前言一、整合mybatis-plus二、CRUD操作1、insert操作2、update操作3、delete操作 三、条件构造器(Wrapper)QueryWrapperUpdateWrapperLambdaQueryWrapperLambdaUpdateWrapper 四、分页查询五、自定义主键生成器六、总结 前言 mybatis相信都不陌生,目前互联…...
Vue2学习记录
前言 这篇笔记,是根据B站尚硅谷的Vue2网课学习整理的,用来学习的 如果有错误,还请大佬指正 Vue核心 Vue简介 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。 它基于标准 HTML、CSS 和 JavaScr…...
thinkphp中对请求封装
请求的封装 //调用 $res Http::post($this->baseUrl . $url,$params,[CURLOPT_HTTPHEADER > [Content-Type: application/json,Content-Length: . strlen($params),],]);<?php namespace fast; /*** 字符串类*/ class Http {/*** 发送一个POST请求*/public static …...
网络安全中的数据科学如何重新定义安全实践?
组织每天处理大量数据,这些数据由各个团队和部门管理。这使得全面了解潜在威胁变得非常困难,常常导致疏忽。以前,公司依靠 FUD 方法(恐惧、不确定性和怀疑)来识别潜在攻击。然而,将数据科学集成到网络安全中…...
通过指令导入/导出vscode扩展插件
导出扩展: 打开VSCode终端: 在VSCode中,你可以通过菜单栏的“终端”选项打开终端,或者使用快捷键Ctrl (反引号,通常在键盘左上角)。运行导出命令: 在终端中,输入以下命…...
vscode添加环境变量(mujoco)
文章目录 前言一、创建.env文件二、编写setting.jason 前言 之前一直用pycharm,最近改用cursor了,在pycharm中设置环境变量修改运行配置就行了,vscode要麻烦一些,记录一下。 一、创建.env文件 以mujoco环境变量为例,…...
0-1背包问题(1):贪心算法
问题: 有 n 个物品和背包的容量,每个物品的重量为 w[i],价值为 v[i],背包的容量为 W。选若干个物品放入购物车,物品不可分割,使价值最大。 问题分析: 首先考虑贪心策略: 每次挑选…...
Qt界面篇:QMessageBox高级用法
1、演示效果 2、用法注意 2.1 设置图标 用于显示实际图标的pixmap取决于当前的GUI样式。也可以通过设置icon pixmap属性为图标设置自定义pixmap。 QMessageBox::Icon icon(...
计算机操作系统——进程控制(Linux)
进程控制 进程创建fork()函数fork() 的基本功能fork() 的基本语法fork() 的工作原理fork() 的典型使用示例fork() 的常见问题fork() 和 exec() 结合使用总结 进程终止与$进程终止的本质进程终止的情况正常退出(Exit)由于信号终止非…...
游戏引擎学习第23天
实时代码编辑功能的回顾 当前实现的实时代码编辑功能已经取得了显著的成功,表现出强大的性能和即时反馈能力。该功能允许开发者在修改代码后几乎立即看到变化在运行中的程序中体现出来,极大提升了开发效率。尽管目前的演示内容较为简单,呈现…...
0基础学java之Day25
Vector /** 知识点:Vector独有的方法 理解: * Vector在JDK1.0开始就已经存在 -- 元老级别的集合类, * 集合框架的概念是JDK1.2开始才有的, * 开发人员为了将Vector保留下来…...
android集成FFmpeg步骤以及常用命令,踩坑经历
1、入坑第一步:首先集成的库必须正确。最好是有ndk的,FFmpeg有许多个版本,我才开始接触的时候随便选了一个,一般的 方法没有问题。但是涉及到需要使用libx264等条件进行编码时,老是报错,网上搜索资料也没有人说需要ndk的支持才行。这个问题困扰了好几天,怎么试不行,最后…...
Mac——鼠标增强插件Mos
功能说明: 能够解决鼠标断续、不灵敏等鼠标问题。 下载地址: Mac——鼠标增强插件Mos...
【c++篇】:解读Set和Map的封装原理--编程中的数据结构优化秘籍
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:c篇–CSDN博客 文章目录 前言一.set和map的初步封装1.树的节点封装修改2.Find()查找函数3.红…...
华为鸿蒙内核成为HarmonyOS NEXT流畅安全新基座
HDC2024华为重磅发布全自研操作系统内核—鸿蒙内核,鸿蒙内核替换Linux内核成为HarmonyOS NEXT稳定流畅新基座。鸿蒙内核具备更弹性、更流畅、更安全三大特征,性能超越Linux内核10.7%。 鸿蒙内核更弹性:元OS架构,性能安全双收益 万…...
ArcGIS API for Javascript学习
一、ArcGIS API for Javascript 介绍 ArcGIS API for Javascript 是由美国 Esri 公司推出,跟随ArcGIS 9.3 同时发布的,是Esri 基于dojo 框架和 REST 风格实现的一套编程接口。通过 ArcGIS API for Javascript可以对ArcGIS for Server 进行访问ÿ…...
LeetCode 3206.交替组 I:遍历
【LetMeFly】3206.交替组 I:遍历 力扣题目链接:https://leetcode.cn/problems/alternating-groups-i/ 给你一个整数数组 colors ,它表示一个由红色和蓝色瓷砖组成的环,第 i 块瓷砖的颜色为 colors[i] : colors[i] …...
环形缓冲区
什么是环形缓冲区 环形缓冲区,也称为循环缓冲区或环形队列,是一种特殊的FIFO(先进先出)数据结构。它使用一块固定大小的内存空间来缓存数据,并通过两个指针(读指针和写指针)来管理数据的读写。当任意一个指针到达缓冲区末尾时,会自动回绕到缓冲区开头,形成一个"环"。…...
Maven 仓库
Maven 仓库对于管理构建 Java 项目所需的依赖和插件至关重要。 Maven 仓库主要有三种类型:本地仓库、中央仓库和远程仓库。 本文将探讨每种仓库的用途以及如何有效使用它们。 Maven 仓库类型 本地仓库 本地仓库是位于您本地机器上的一个目录,Maven 在…...
29.UE5蓝图的网络通讯,多人自定义事件,变量同步
3-9 蓝图的网络通讯、多人自定义事件、变量同步_哔哩哔哩_bilibili 目录 1.网络通讯 1.1玩家Pawn之间的同步 1.2事件同步 1.3UI同步 1.4组播 1.5变量同步 1.网络通讯 1.1玩家Pawn之间的同步 创建一个第三人称项目 将网络模式更改为监听服务器,即将房主作为…...
计算机网络习题解答--个人笔记(未完)
本篇文章为关于《计算机网络-自顶向下方法第七版》的阅读总结和课后习题解答(未完待续) 第二章: cookie:(这里是比较老版本的HTTP,具体HTTPs是怎么实现的不是很清楚)cookie的原理其实很简单。就是在HTTP消息头上又多…...
Unity图形学之雾Fog
1.设置雾化: 2.雾化变化曲线:FogMode (1)线性: (2)一次指数: (3)二次指数: Shader "Custom/FogTest" {Properties{_Color ("Color…...
ML 系列:第 36 节 — 统计学中的抽样类型
ML 系列:第 36 天 — 统计学中的抽样类型 文章目录 一、说明二、抽样方法三、简单随机抽样四、 Stratified Sampling分层抽样五、 Cluster Sampling 整群抽样六、Systematic Sampling系统抽样七、Convenience Sampling便利抽样八、结论 一、说明 统计学中的抽样类型…...
docker-compose部署java服务
文章目录 一、下载安装docker-compose二、编写Dockerfile文件三、编写docker-compose.yml文件配置说明 四、服务启动五、测试与验证 一、下载安装docker-compose 在安装docker时,并不会同时把docker-compose安装好,需要额外安装一下 下载docker-compos…...
ubuntu22开机自动登陆和开机自动运行google浏览器自动打开网页
一、开机自动登陆 1、打开settings->点击Users 重启系统即可自动登陆桌面 二、开机自动运行google浏览器自动打开网页 1、安装google浏览器 sudo wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo dpkg -i ./google-chrome-stable…...
java接口对接标准
概述 最近在跟许多外部平台对接,遇到了很多问题,在此记录一下接口的对接标准。 接口对接标准 确认环境,分别获取di和prd环境的接口信息,比如域名。确认不同环境的防火墙是否连通。接口校验,接口携带的token信息如何…...
训练的decoder模型文本长度不一致,一般设置为多大合适,需要覆盖最长的文本长度么
在训练解码器模型时,文本长度不一致是常见的情况,需要根据任务的特性和数据集的长度分布来设置合理的最大长度 (max_length)。以下是一些指导原则,帮助你设置合适的最大长度: 1. 是否需要覆盖最长文本长度 覆盖最长文本长度: 如果任务对完整性要求很高(例如生成数学公式、…...
安装MySQL服务
安装版本MySQL8的安装包 安装界面 在这里选择MySQL中的Server only 只安装服务器端 如果选择custom需要如下图 进入配置导向,点击ready to configure,点击next即可 采用默认形式 执行成功后,会出现自动选择项 点击next然后再点击Finish 启动…...
十二、正则表达式、元字符、替换修饰符、手势和对话框插件
1. 正则表达式 1.1 基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&g…...
Unreal从入门到精通之如何绘制用于VR的3DUI交互的手柄射线
文章目录 前言实现方式MenuLaser实现步骤1.Laser和Cursor2.移植函数3.启动逻辑4.检测射线和UI的碰撞5.激活手柄射线6.更新手柄射线位置7.隐藏手柄射线8.添加手柄的Trigger监听完整节点如下:效果图前言 之前我写过一篇文章《Unreal5从入门到精通之如何在VR中使用3DUI》,其中讲…...
如何提升编程能力第二篇
如何提升编程能力2 1. 引言2. 掌握理论基础2.1 理解编程语言的核心2.2 数据结构与算法2.3 计算机基础与系统设计3.1 多写代码3.2 参与开源项目3.3 开发自己的项目 4. 提高代码质量4.1 代码风格与可读性4.2 测试驱动开发 1. 引言 编程是推动现代科技发展的核心技能,…...
【AI日记】24.11.26 聚焦 kaggle 比赛
【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 核心工作 1 内容:研究 kaggle 比赛时间:3 小时 核心工作 2 内容:学习 kaggle 比赛 Titanic - Machine Learning from Disaster时间:4 小时备注:这…...
计算机网络八股整理(一)
计算机网络八股文整理 一:网络模型 1:网络osi模型和tcp/ip模型分别介绍一下 osi模型是国际标准的网络模型,它由七层组成,从上到下分别是:应用层,表示层,会话层,传输层,…...
删除链表中的重复元素
删除链表中的重复元素 单链表的创建和使用删除链表中的重复元素 I题目描述解题思路代码实现 删除链表中的重复元素 II题目描述解题思路代码实现 单链表的创建和使用 使用vector结合单链表数据结构创建一个通用单链表。 #include <iostream> #include <vector>str…...
序列求和 牛客网
链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 定义S(n) 12 22 … n2,输出S(n) % 1000000007。 注意:1 < n < 1e18。 输入描述: 多组输入,输入直到遇到EOF为止;第一行输…...