c++11新内容补充
1.列表初始化
1.1传统{ }初始化
c++98的{ }初始化主要是用于数组,以及结构体
1.2c++11{ }初始化
1.让内置类型和自定义类型都可以用{ }实现多个数据初始化,而自定义类型的实现原理是类型转换(没优化的版本是先构造临时对象,然后拷贝构造)
2.我们在使用{ }时也可以省略掉=直接用{ }
场景:主要用于传递多参数进行初始化
1.3initializer_list
initiallizer_list是一个库中实现的类,底层是由一个指向常量数组的指针(包含头指针和尾指针)和数据个数封装的类
使用场景:主要用于写模板类等底层场景的任意数量数据的构造
vector(initializer_list<T> l) { for (auto e : l) {push_back(e) } }
这里就以vector的任意数量数据的构造为例,通过initiallizer_list我们就实现了任意数量的数据的构造
2.右值引用与移动语义
2.1左值与右值的概念
左值:是变量表达式,一般有持久状态,可以取地址
常见左值举例:
// 左值:可以取地址int* p = new int(0);//指针int b = 1;//整形变量const int c = b;//const整形变量string s("111111");//字符串变量
右值:一般是字面值常量,临时对象,匿名对象,不能取地址,不能放在赋值符号左边。
常见右值举例:
//右值不能取地址double x = 1.1, y = 2.2;//下面为常见右值10;//字面值常量x + y;//临时变量fmin(x, y);//临时对象string("11111");//匿名对象
2.2左值引用与右值引用
引用就是给变量取别名,右值引用也是一样的。只不过左值引用引用的是左值,右值引用引用的是有右值。
左值引用:
(1)引用左值:&
(2)引用右值:const &
//左值引用//引用左值int a = 0;int& b = a;//引用右值const int& c = 10;
右值引用:
(1)引用右值:&&
(2)引用左值:将左值move为右值类型再用&&
//右值引用//引用右值int&& d = 10;//引用左值int&& e = move(a);
move的底层就是强制类型转换,可看成将左值move强制类型转换为右值,然后用右值引用。
!!!:变量表达式都是左值属性,所以绑定右值的右值引用变量也是左值属性
2.3引用延长变量生命周期
我们知道,临时变量,匿名对象,临时对象都是生命周期为当前行的数据。而此时使用右值引用去绑定该数据后,他们的生命周期就被延长到引用的生命周期了
10;//生命周期为当前行int&& f = 10;//生命周期为f的生命周期
2.4左值右值参数匹配
在c++中我们的函数参数匹配通常是遵守匹配度优先的原则,这里的右值引用参数,左值引用参数匹配也是一样,优先匹配更匹配的
接下来我们实现了左值引用,const左值引用,右值引用三种参数匹配函数,分别测试三种类型的匹配结果
这里就是按照原本的数据类型进行匹配
接下来我们将右值引用注释掉,再次查看参数匹配结果
我们发现此时右值被const左值引用绑定了,这说明不能完全匹配的时候才会考虑其他的类型匹配
2.5左值引用使用场景
左值引用使用场景:
1.通过传引用,减少拷贝
2.可以通过引用的改变来影响实参
左值引用没有解决的场景:
对于返回的局部变量,返回左值引用也没用,因为局部变量出函数就已经被销毁了,那右值引用有没有用?
其实也没有用,因为只要是引用就是取别名,他引用的对象都被销毁了,返回的就是一个悬空引用。
2.5.1移动构造与移动赋值
我们解决左值引用不足的方法就是使用移动语义。
具体来说就是多写一个移动构造和移动赋值,通过右值引用作为参数去接收生命周期快结束(不一定本身是右值)的数据,然后延长他们的生命周期到移动函数结束时,通过直接swap的方式将右值数据的内容接收下来。
移动构造:
对于右值,匹配时直接匹配,对于左值,匹配前先用move将左值类型转换为右值,然后再匹配
// 移动构造 string(string&& s) { cout <<"移动构造" << endl; swap(s); }
添加了移动构造之后,对于效率的提升是很明显的,既没有多余空间申请,也没有时间上多余的消耗
移动赋值:
// 移动赋值 string& operator=(string&& s) { cout << "移动赋值" << endl; swap(s); return *this; }
移动赋值也是一样的,直接将资源交换即可
2.5.2解决传值返回多余拷贝问题
场景1:右值对象构造,只有拷⻉构造,没有移动构造的场景
图示:
不优化情况下进行两次拷贝构造
优化情况进行一次拷贝构造,这里直接越过了临时对象的构建
场景2:右值对象构造,有拷⻉构造,也有移动构造的场景
图示:
不优化情况下进行两次移动构造,因为str是生命周期即将结束的变量,所以使用移动语义可以有效提高效率
优化1情况下进行一次移动构造,这里也是省略掉临时对象
优化2情况下会将str的构造,str给临时对象的拷贝构造,临时对象给main中对象的拷贝构造合并为对main中对象的构造。
场景3:右值对象赋值,只有拷⻉构造和拷⻉赋值,没有移动构造和移动赋值的场景
图示:
不优化情况下进行一次拷贝构造,一次拷贝赋值。
优化情况下进行一次拷贝赋值,优化的部分是提前构造出临时对象,然后str是临时对象的引用,最后让临时对象移动赋值给main中对象
场景4:右值对象赋值,既有拷⻉构造和拷⻉赋值,也有移动构造和移动赋值的场景
图示:
不优化情况下进行一次移动构造,一次移动赋值。
优化情况下进行一次移动赋值
总结:
在有编译器优化的情况下,没有移动构造和移动赋值也没有问题,但是如果没有编译器的优化,此时就需要我们写移动构造和移动赋值来提高效率
3.引用折叠
在模板中,我们不可避免的会存在引用的引用的情况,但是如果我们直接int& &&a;这样来定义的话,会直接报错。可以通过模板或typedef来达成目的
引用折叠原则:右值引用叠加右值引用为右值引用,其他情况都为左值引用
//引用折叠int n = 0;typedef int& l;typedef int&& r;l& a = n;//左值叠左值-》左值引用l&& b = n;//左值叠右值-》左值引用r& c = n;//右值叠左值-》左值引用r&& d = 1;//右值叠右值-》右值引用
接下来我们看看用const左值引用和用const右值引用当函数参数有什么不同
//const左值引用 template<class T> void f1(const T& a) { }
//const右值引用 template<class T> void f2(const T&& b) { }
左值引用当参数的时候,传的参数无论是左值还是右值,根据引用折叠的规则,他的结果都是左值引用
右值引用当参数的时候,传的参数是左值,那么最终折叠完就是左值。传的参数是右值,最终折叠完就是右值,我们发现我们传的参数是什么类型,最终的结果就是什么类型的引用。所以由实参决定T类型的右值引用当参数又被称为万能引用
也就是template要直接在该方法前面,T由参数决定
我们思考一下再一个类中的const T&&属不属于万能引用?
假设我们用的是vector中的push_back方法,这个方法中的T的类型不是由实参决定的,而是由vector类决定的,所以这里不存在引用折叠,直接就是一个确定的引用类型。
4.完美转发
虽然我们前面利用引用折叠弄出了一个万能引用,但是在万能引用模板中我们就不能使用move这个方法去强制类型转换变量了,因为我们不确定变量是左值引用的还是右值引用的。
为了能够正确的匹配对应的函数,我们会使用一个叫完美转发的方法来保持变量的属性,原本是左值就保持左值,是右值就保持右值
完美转发:forward<T>(变量名),其中T表示实参的数据类型
template<class T> void f2(const T&& b) {f1(forward<T>(b)); }
完美转发的底层是一个模板函数,对左值引用和右值引用有不同的函数体进行变量属性控制。而我们在这里这样使用相当于显式实例化函数模板,根据这个实例化出的函数的逻辑对右值move从而保持变量属性。在这里就保持了b的属性值是左值或右值。
5.可变参数模板
在c++中有一种模板是支持从0到任意个参数的,也就是可变参数模板。
可变数目参数被称为参数包,参数包又分两种:第一种是函数参数包,第二种是模板参数包
我们利用...来指出接下来的参数是一个包
函数参数中:类型名后面接的参数表示0到n个形参
模板参数中:typename...、class...后面接的参数表示0到n个类型参数。
5.1基本语法格式
//可变模板参数 template<class... Args> void function(Args&&... args) {}
模板位置的写法就是class...然后接可变模板类型名,函数参数位置的写法就是类型名...接形参名。
本质上是实现了类型泛型基础上的个数泛型
补充:sizeof...(args)可以求可变参数的个数
5.2包扩展
void Extend() {// 参数包无参数需要扩展时,匹配这个函数cout << "扩展结束" << endl; } template <class T, class ...Args> void Extend(T x, Args... args) {cout << x << " ";// args是N个参数的参数包// 调⽤Extened,参数包的第⼀个参数传给x,剩下N-1个参数的参数包传给第⼆个参数包Extend(args...); } // 编译时递归推导解析参数 template <class ...Args> void Print(Args... args) {Extend(args...); }
我们可以利用递归函数来对包进行扩展,这里的extend就是递归扩展函数。第一步扩展就是实例化出一个对应的Extend函数,该函数先将包中的第一个参数给到Extend的x参数,然后将剩下的包给到Extend的第二个包参数,如此递归进行。直到包中数据为0,我们就匹配无参数的Extend函数。
注意:
与普通递归函数不同的是,包扩展的递归是编译时进行的,而不是运行时进行的
接下来我们看看另外一个包扩展方法
template <class T> const T& GetArg(const T& x) {cout << x << " ";return x; } template <class ...Args> void Arguments(Args... args) {} template <class ...Args> void Print(Args... args) {Arguments(GetArg(args)...); }
注意:
1.getarg必须有返回值:因为他的所有返回值又构成了一个参数包给到argument2.由于进入一个函数之前要先处理参数,参数中有函数的话我们就先进入参数中的函数,在参数函数处理完之后我们再进入函数体
3.这里的GetArg(args)...可以看为:GetArg(x1),GetArg(x2),GetArg(x3),其中x1,x2,x3都是包中的参数
5.3emplace系列接口
在c++的库中,所有的容器都添加了emplace系列的接口,他的参数部分是由万能引用叠加可变模板参数组成的。整体而言他的效率要比普通的接口要高
接下来我们看看在什么场景下emplace系列效率要更高
list<string> li; li.push_back("11111"); li.emplace_back("111111");
首先我们看看push_back的参数要求
由于push_back的模板参数是在对象实例化的时候就确定了,所以value_type的类型是string。而我们这里传的是右值,所以匹配的就是类型string&&。
可是"11111"的类型是const char*,参数匹配类型不一样,所以我们要进行类型转换,创建一个临时变量,然后再匹配参数。此时我们就需要进行一次构造
然后是emplace_back的参数要求
由于emplace_back的模板参数是根据传递的参数决定的,所以函数参数被实例化为
const char*&&,我们可以直接进行参数匹配,不用进行构造
综上,push_back需要传递参数时要进行一次构造,而emplace_back不需要进行构造,这里就体现出emplace_back的效率更高
注意:
1.emplace系列传递多参数不用加{},因为参数是可变模板参数,且如果我们加了{}会导致编译器无法识别参数类型,pair中的变量是什么类型是不明确的。
6.lambda
6.1表达式语法
他是一个匿名函数对象,可以定义在函数体内部。不过他没有语法层面的数据类型,我们一般用auto去充当接收类型
接下来我们写一个加法功能的lambda:
//Lambdaauto y = [](int a, int b)->int {return a + b; };cout << y(1, 2) << endl;
右侧的lambda实际上就是一个对象。
[ ]:方括号中的就是捕捉列表,主要用于确定需要使用的lambda函数外部的参数
():小括号中的就是函数参数列表,可省略
->:后面的是函数返回值类型,可省略
{}:大括号内是函数体
简化lambda:
//简化Lambdaauto x = [] {cout << "简化lambda" << endl; };x();
使用方式:和使用普通函数的方法一样
6.2捕捉列表
lambda的表达式默认只能使用参数和函数体内的变量,若我们需要使用这两个位置之外的变量就需要通过捕捉列表进行捕捉
第一种捕捉方式:传值捕捉与传引用捕捉
传值捕捉传的值在lambda中不能被修改,传引用捕捉的值在lambda中可以被修改,不过需要注意的是传引用捕捉的值改变的也只是形参,而不会影响实际的参数的值
//传值捕捉与传引用捕捉int a = 1, b = 2;auto e = [a, &b] {b++;return b;};
这里的a在lambda中无法修改,b在lambda中可以修改,且由于是引用,所以实参b也被修改了
第二种捕捉方式:隐式值捕捉与隐式引用捕捉
这两种捕捉方式又叫全捕捉,因为只要用了他们就可以使用其他所有变量,需要注意的是这两种捕捉方式不能同时使用,因为这样就不知道到底是要值还是引用了
//隐式值捕捉与隐式引用捕捉int a = 1, b = 2;auto e = [&] {//隐式引用捕捉b++;return b;};auto f = [=] {//隐式值捕捉return a;};
这种情况下,我们在函数中用到了哪些变量,就会捕捉哪些变量,而不是真正的全都捕捉下来
第三种捕捉方式:混合捕捉
这里我们就可以使用隐式值捕捉/隐式引用捕捉+引用捕捉/值捕捉
//混合捕捉int c = 3, d = 4;auto g = [&, c] {//隐式引用混合值捕捉d++;return 0;};auto g = [=, &d] {//隐式值混合引用捕捉d++;return 0;};
注意:
1.隐式值/引用捕捉只能出现一个,不能同时出现。
2.隐式值/引用捕捉需要放在第一个位置,不能放在后面
3.隐式值后面只能接引用捕捉,同理隐式引用后面只能接值捕捉
(1)当lambda定义在函数局部域中,可以捕捉在他之前定义的局部变量,不能捕捉静态局部变量和全局变量,但是他可以直接使用这两种变量。也就是说,如果lambda定义在全局域中,捕捉列表必须为空。
(2)传值过来的变量默认有const修饰,所以不可修改,但是如果加了mutable修饰就可以把const属性去掉,然后我们就可以修改传值捕捉的变量了。
但是他实际上还是一个拷贝变量,改变的只是形参,而不是实参
6.3应用
我们思考一个场景,当我们需要用水果的某个指标进行排序,此时我们可以使用仿函数控制排序逻辑,但是这样我们需要在全局域定义一个新的仿函数,且该仿函数唯一作用也就是这个地方,此时会导致代码全局域冗余。
那么我们有没有什么其他方法控制排序逻辑,使得我们可以不在全局域上定义新的仿函数?
此时我们就可以使用lambda,将sort的仿函数传参位置写上一个lambda对象,对对应逻辑进行控制
//比较场景struct fruit {int price;string colour;fruit(int prices,string colours):price(prices),colour(colours){}};vector<fruit> v = { {1,"red"},{2,"yellow"},{3,"blue"}};sort(v.begin(), v.end(), [](const fruit& a, const fruit& b)->int {return a.price > b.price; } );
这里我们创建一个水果结构体,然后通过lambda实现按照水果的价格进行排序
注意:在调试的时候如果我们把断点打在了sort上面,会直接进入sort中,不方便查看lambda的功能,此时我们可以进入一次sort后就直接将sort的断点取消掉
6.4原理简介
lambda和范围for很像,他们实际上都是封装出来的,lambda底层就是一个仿函数的类
捕捉列表:实际上就是生产在仿函数中的成员变量
参数列表:operator()中的传参
返回值:operator()的返回值
函数体:operator()的函数体
7.新的类功能
7.1默认的移动构造和移动赋值
默认生成移动构造的前提:没有自己实现移动构造,且没有实现析构函数 、拷⻉构造、拷⻉赋值重载中的任意⼀个。
默认生成移动赋值的前提:没有⾃⼰实现移动赋值重载函数,且没有实现析构函数 、拷⻉构造、拷⻉赋值重载中的任意⼀个
7.2default和delete
default的作用是显式指定编译器去实现默认的特殊成员函数:一共有六个(分别是构造,拷贝构造,赋值重载,移动构造,移动赋值,析构函数)
用法:以移动构造的指定生成为例
Person(Person&& p) = default;
delete的作用和default刚好相反,他是可以阻止某个默认特殊函数的生成
用法:以默认生成移动构造的阻止为例
Person(Person&& p) = delete;
这里其实就相当于将默认特殊函数的函数体外的部分写在前面,然后接个=和修饰符来控制默认特殊函数的生成和阻止生成
8.包装器
8.1function(处于functionnal头文件)
在c++中有很多的可调用对象,比如:函数指针,仿函数,lambda,bind等。他们的使用是分开来使用的,而function的作用就是将他们统一起来(在返回值的参数都一样的前提下)
function包装的对象称为function的目标
这里我们看到他的模板参数中有ret(返回值),args(可变模板参数)
格式:function<返回值类型(参数)> fn[] = {}
这里的function<返回值类型(参数)>就是一个类型
接下来我们看看使用样例来理解他的优势
这里我们就是将返回值为int,参数都为两个整形的加减乘法包装在function中,从而实现根据索引调用不同的函数的目的,也就是我们把分开的加减乘三个函数统一到了function函数中。
包装可调用对象:
// 包装各种可调⽤对象 function<int(int, int)> f1 = f; function<int(int, int)> f2 = Functor(); function<int(int, int)> f3 = [](int a, int b) {return a + b; };
包装静态成员函数:
// 成员函数要指定类域并且前⾯加&才能获取地址 function<int(int, int)> f4 = &Plus::plusi; cout << f4(1, 1) << endl;
其实静态成员函数是不用加&的,但是普通成员函数需要,所以为了统一我们就一起都加上
包装普通成员函数:
// 普通成员函数还有⼀个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以function<double(Plus*, double, double)> f5 = &Plus::plusd;//传指针 Plus pd; cout << f5(&pd, 1.1, 1.1) << endl;function<double(Plus&, double, double)> f6 = &Plus::plusd;//传左值引用 cout << f6(pd, 1.1, 1.1) << endl; cout << f6(pd, 1.1, 1.1) << endl;function<double(Plus&&, double, double)> f7 = &Plus::plusd;//传右值引用 cout << f7(move(pd), 1.1, 1.1) << endl; cout << f7(Plus(), 1.1, 1.1) << endl;
疑问:为什么普通成员函数的包装多了一个传递参数?
因为成员函数本身就隐含了一个指向调用该函数的对象的指针,也就是
this
指针。在调用成员函数时,编译器会自动把调用对象的地址当作第一个参数传递给成员函数。
- 使用指针调用成员函数:借助
->
运算符来调用成员函数,其实质是将指针所指向的对象地址传递给成员函数。- 使用引用调用成员函数:通过
.
运算符调用成员函数,编译器会把引用转换为对象的地址,然后传递给成员函数。所以本质上我们都是为了成员函数能借助我们传递的对象地址,正确调用函数
接下来我们看看function的整合优势:
map<string, function<int(int, int)>> opFuncMap = { {"+", [](int x, int y){return x + y;}}, {"-", [](int x, int y){return x - y;}}, {"*", [](int x, int y){return x * y;}}, {"/", [](int x, int y){return x / y;}} };
这里我们就把加减乘除的字符串和对应的运算函数通过map的k-v特性联系起来了,而在这里function充当了调用函数类型的作用,正是有了function我们才能实现将字符串和对应函数联系起来的功能
8.2bind
bind的作用是调整可调用对象的参数个数与顺序,然后返回一个调整后的新的可调用对象
实例1:调整参数位置
#include<functional> using placeholders::_1; using placeholders::_2; using placeholders::_3; int Sub(int a, int b) {return (a - b) * 10; }
bind也是包含在头文件functionnal中的,然后placeholders作用域中的_1,_2,_3等等就是占位符。
这里我们把第一个参数和第二个参数的传递顺序改变了,也就是我们传递的参数a是4,参数b是3,从而得出结果为10.
实例2:调整参数个数(绑定一些参数)
这里我们就把第一个参数a给绑定为100,从而实现调整参数个数的目标。
我们在绑定参数的时候是按照原本的参数顺序绑定的,因为绑定了参数a为100,所以只剩下一个参数需要传递,所以后面只剩下_1占位符,传递给参数b。
总结:有几个参数就有几个占位符,绑定参数是按照原本的顺序绑定的
我们是否可以将function和bind结合使用,从而简化代码?
function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2); cout << f7(1.1, 1.1) << endl;
这里我们本来是对普通函数进行function包装,需要传递对象指针/引用,但是每次使用包装函数都要传一次就比较麻烦,所以我们直接用bind绑定对象引用,然后返回绑定后的调用对象,从而以后每次使用都不用再传递对象的引用了
相关文章:
c++11新内容补充
1.列表初始化 1.1传统{ }初始化 c98的{ }初始化主要是用于数组,以及结构体 1.2c11{ }初始化 1.让内置类型和自定义类型都可以用{ }实现多个数据初始化,而自定义类型的实现原理是类型转换(没优化的版本是先构造临时对象,然后拷贝构…...
动态规划基础
动态规划 动态规划概论楼梯最短路最长上升子序列(LIS)最长公共子序列(LCS)最长回文子串 概率动态规划区间动态规划石子合并括号序列石子合并(环形) 树形动态规划统计人数没有上司的舞会 背包01背包完全背包多重背包分组背包 动态规…...
导入 Excel 批量替换文件名称及扩展名
重命名的需求是多种多样的,我们一个方法或一个工具很难说完全满足 100% 的文件重命名的需求。如果我们的文件重命名的需求非常的复杂的时候,我们能否有一个万全的方法来帮我们实现呢?那今天就给大家介绍一下导入 excel 的方式批量修改文件名称…...
降低AIGC检测率的AI润色提示词模板
以下是针对降低AIGC检测率的 AI润色提示词模板,涵盖语言风格优化、逻辑重构、学术规范强化等维度,结合反检测策略设计,可直接用于DeepSeek等工具: 一、标题与摘要优化 1. 标题去AI化 提示词: 请将以下标题改写成更学…...
系统思考—提升解决动态性复杂问题能力
感谢合作伙伴的信任推荐! 客户今年的人才发展重点之一,是提升管理者应对动态性、复杂性问题的能力。 在深入交流后,系统思考作为关键能力模块,最终被纳入轮训项目——这不仅是一次培训合作,更是一场共同认知的跃迁&am…...
spring--整合Mybatis详解
整合Mybatis 步骤: 1.导入相关Maven依赖 junit mybatis mysql数据库连接 spring相关的 aop织入 mybatis-spring 2.编写配置文件 3.测试 回忆mybatis 还需连接数据库 导入依赖: <dependencies><dependency><groupId>juni…...
深入理解 HTML5 Audio:网页音频播放的新时代
在网页开发领域,音频的嵌入和播放一直是一个重要且不断演进的话题。HTML5 的出现,为网页音频播放带来了标准化的解决方案,极大地改善了开发者和用户的体验。 一、HTML5 之前的音频播放状况 在 HTML5 诞生之前,互联网上缺乏统一的网页音频播放标准。当时,大多数音频播放依…...
Cloudflare 缓存工作原理
Cloudflare 缓存是 Cloudflare 内容分发网络(CDN)的一个关键组成部分,通过在靠近用户的全球网络边缘服务器上存储和交付内容,显著提升网站性能。以下是关于 Cloudflare 缓存的相关内容: 工作原理 内容请求:…...
【Unity3D中UI与物体可见性的判断方法】
系列文章目录 unity知识点 文章目录 系列文章目录👉前言👉一、判断UI的可见性1-1、第一种1-2、通过RectTransform计算可视区域1-3、滚动容器内可见性检测(Scroll View) 👉二、判断物体的可见性2-1、视锥体检测方法2-2…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(1):承上启下,继续上路
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(1):承上启下,继续上路 1、前言(1)情况说明(2)工程师的信仰2、知识点(1)普通形(ふつうけい)と思います(2)辞書形ことができます(3)Vたことがあります。(4)Vた とき & Vる とき3、单词(1)日语单词(2…...
ubuntu24.04 cmake 报错 libldap-2.5.so.0 解决办法
apt cmake有毛病 换源重新安装 wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add - sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" sudo apt update sudo apt in…...
Mac 关闭浏览器左右滑动切换页面的问题
在使用触控板,操作浏览器时,左右滑动时,浏览器容易触发前进或者后退去查看历史记录。 如何关闭呢? 打开Mac- 系统设置-触控板 -更多手势 将轻扫切换页面设置为关,就可以了...
在 openEuler 24.03 (LTS) 操作系统上添加 ollama 作为系统服务的步骤
以下是在 openEuler 操作系统上添加 ollama 作为系统服务的步骤: 创建 systemd 服务文件 sudo vi /etc/systemd/system/ollama.service将以下内容写入服务文件(按需修改参数): [Unit] DescriptionOllama Service Afternetwork.…...
华为昇腾服务器上查看固件、驱动和CANN版本的常用方法
Hey小伙伴们~👋 今天来聊聊怎么在华为昇腾服务器上查看固件、驱动和CANN版本吧!💻 这些信息对于确保你的服务器运行顺畅可是超级重要的哦!下面就来给大家介绍几种常用的查看方法!👇 🌟 1. 查…...
击球手怎么玩·棒球1号位
以棒球运动为例,在棒球运动中,击球手(Batter)是进攻方的核心角色,负责通过击球创造得分机会。以下是结合棒球运动的详细介绍和击球技巧指南: 一、棒球基础规则 比赛目标 击球手需将投手(Pitch…...
java基础多态------面试八股文
是什么是多态 类引用指向子类对象,并调用子类重写的方法,实现不同的行为 例子 class Animal {void sound() {System.out.println("动物发出声音");} }class Dog extends Animal {Overridevoid sound() {System.out.println("狗叫&…...
Python中的字典
文章目录 一、Python中的字典1. 字典的特点2. 字典的创建3. 字典的常见操作1. **访问字典中的值**2. **修改字典中的值**3. **添加键值对**4. **删除键值对**5. **检查键是否存在**6. **获取字典的长度**7. **遍历字典** 4. 字典的方法5. 嵌套字典6. 字典的优点7. 示例总结 二、…...
C++对象生命周期管理:从构造到析构的完整指南
在C开发中,准确掌握对象的生命周期管理是避免内存泄漏和资源竞争的关键。本文通过完整代码示例和内存布局分析,深入解析构造/析构顺序、继承体系、智能指针等核心机制,并分享实用调试技巧。 一、成员变量构造顺序:声明即命运 cl…...
代码随想录第14天:(二叉树)
一、找树左下角的值(Leetcode 513) 递归法: class Solution:def findBottomLeftValue(self, root: TreeNode) -> int:# 初始化最大深度为 -1,表示当前尚未遍历任何节点# 初始化 result 为 None,最终将存储最左边的…...
TCP/UDP的连接和数据发送过程详解
TCP TCP三次握手 在服务端启动好后会调用 listen() 方法,进入到 LISTEN 状态,然后静静等待客户端的连接请求到来。 而此时客户端主动调用 connect(IP地址) ,就会向某个IP地址发起第一次握手,会先建立个半连接,发送SYN…...
2. 单词个数统计
【问题描述】 编写一个程序,输入一个句子,然后统计出这个句子当中不同的单词个数。例如,对于句子“one little two little three little boys",总共有5个不同的单词,one, little, two, three, boys。 说明&…...
Js生成螺旋数组。
这段代码定义了一个名为 vetux 的函数,用于生成一个螺旋矩阵。螺旋矩阵是一种按照螺旋顺序填充数字的二维数组。以下是代码的详细解释: 函数定义 function vetux(n, m) {// 创建一个 m 行 n 列的二维数组,初始值为 0const a new Array(m).…...
《Vue.js组件化开发实战:从安全纵深到性能跃迁》
开篇:组件化开发的工业革命 当全球500强企业的核心业务系统在12.12大促中经受每秒38万次请求冲击时,我们突然意识到:现代前端组件已不再是简单的UI积木,而是承载业务逻辑、安全防护、性能优化的纳米级作战单元。本文将从军工级系统…...
【Git】--- 多人协作实战场景
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: Git 前面我们学习了Git的所有本地仓库的相关操作:git基本操作,分支理解,版本回退,冲突解决等等。同时我们还理解了远端仓库在开发的作用以及相关操作push…...
SmolVLM2: The Smollest Video Model Ever(二)
这是对论文《SmolVLM: Redefining small and efficient multimodal models》的整理与翻译 SmolVLM:重新定义小型高效的多模态模型 拥抱脸、斯坦福大学 图1 小而强大:SmolVLM与其他最先进的小型视觉语言模型(VLM)的比较。图像结果来…...
如何通过前端表格控件实现自动化报表?1
背景 最近伙伴客户的项目经理遇见一个问题,他们在给甲方做自动化报表工具,项目已经基本做好了,但拿给最终甲方,业务人员不太买账,项目经理为此也是天天抓狂,没有想到合适的应对方案。 现阶段主要面临的问…...
数据库8(函数,变量)
1.数据类型 char(10):不足十个字符,用空格补全,数据定长;非统一字符编码,一个汉字要占两位char(2) nchar(10):不足十个字符,用空格补全,数据定长;统一字符编码,一个汉字占一位 nch…...
电阻式传感器(三)——电位器式传感器等效电路分析
(1)电位器式传感器的基本工作原理 将机械位移或其他可转换为位移变化的非电量转换为与其有一定函数关系的电阻变化,从而引起输出电压变化。 类型 基本结构 旋转型 直线型 非线性型 (2)电位器式传感器的等效电路分析 电位器式传感器的核…...
LangChain4j(1):初步认识Java 集成 LLM 的技术架构
LangChain 作为构建具备 LLM 能力应用的框架,虽在 Python 领域大放异彩,但 Java 开发者却只能望洋兴叹。LangChain4j 正是为解决这一困境而诞生,它旨在借助 LLM 的强大效能,增强 Java 应用,简化 LLM 功能在Java应用中的…...
力扣刷题——1339.分裂二叉树的最大乘积
给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。 由于答案可能会很大,请你将结果对 10^9 7 取模后再返回。 示例 1: 输入:root [1,2,3,4,5,6] 输…...
Pytest+Allure+Excel接口自动化测试框架实战
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 1. Allure 简介 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具,它不仅以 Web 的方式展示了简介的测试结果,而且允…...
交易所开发全流程解析:KYC与U盾在安全合规中的战略价值
——2025年加密资产交易平台的技术架构与风控体系深度实践 一、交易所开发的核心技术架构与流程 1. 系统定位与合规基础 交易所开发需首先明确中心化(CEX)、去中心化(DEX)或混合架构的定位。中心化交易所(如币安&…...
简单了解一下Unity的Resources.UnloadUnusedAssets
基本概念 Resources.UnloadUnusedAssets()是Unity提供的一个内存管理方法,用于卸载当前未被任何GameObject引用的资源,包括贴图、材质、网格、音频等资源。 在Unity中,资源在加载后会占用内存,而当这些资源不再被场景中的对象引…...
ECMAScript 7~10 新特性
ECMAScript 7 新特性 ECMAScript 6 新特性(一) ECMAScript 6 新特性(二) ECMAScript 7~10 新特性(本文) 1. 数组方法 Array.prototype.includes() 用来检测数组中是否包含指定元素,返回布尔值&…...
leetcode_1. 两数之和_java
1. 两数之和https://leetcode.cn/problems/two-sum/ 1、题目 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你…...
Mysql索引(四)
1、B树:B树即平衡查找树,一般理解为平衡多路查找树,也称为B-树、B_树。是一种自平衡树状数据结构,能对存储的数据进行O(log n)的时间复杂度进行查找、插入和删除; 1)每个节点占用一个盘块的磁盘空间&#x…...
力扣——【1991. 找到数组的中间位置】
#前缀和思想 主要利用递推的思想,将数列的前n!项和存到一个新数列中,递推公式可能需要自己推导 一个数列的值等于另一个数列的第i个元素加上这一个数列的第i-1个元素 同时需要初始化这个数列的第一个元素另一个数列的第一个元素 #思路 本…...
在 Linux 系统(ubuntu/kylin)上安装 Docker
在 Linux 系统上安装 Docker 的步骤如下(以 Ubuntu/Debian 和 CentOS/RHEL 为例): 请用./check-config config检查内核是否支持,necessarily 必须全部enable。 以下是脚本自行复制运行: #!/usr/bin/env sh set -eEXITCODE=0# bits of this were adapted from lxc-checkco…...
【实证分析】数智化转型对制造企业全要素生产率的影响及机制探究(1999-2023年)
数智化转型是实现数字经济与实体经济深度融合,推动制造企业高质量可持续发展的必然选择,也是加快新质生产力发展的重要抓手。参照宋冬林(2025)的做法,对来自科技进步与对策《数智化转型对制造企业全要素生产率的影响及机制探究——基于中国制…...
lower_bound
在C中,lower_bound 返回的是一个迭代器(iterator),而不是直接的下标位置。因此,为了得到数组中的索引(即 pos1),你需要用返回的迭代器减去数组的起始地址(num)…...
biblatex 的 Biber 警告:tex文件运行无法生成参考文献和目录
原因:使用了 biblatex 管理参考文献,但未运行 biber 生成参考文献数据。 解决:更新 LaTeX Workshop 配置 修改你的 settings.json,添加 biber 工具并更新编译流程: {"latex-workshop.latex.tools&…...
解锁 MCP:模型上下文协议的介绍与应用,技术解析与应用场景
欢迎来到涛涛聊AI,这几天MCP很火,咱们一起学习下吧。 一、什么是 MCP MCP,即 Model Context Protocol(模型上下文协议),是由 Anthropic 推出的一个具有创新性的开放协议 。它的核心目标是统一 LLM 应用与外部数据源和工具之间的通信方式,为 AI 开发打造标准化的上下文…...
十二种存储器综合对比——《器件手册--存储器》
存储器 名称 特点 用途 EEPROM 可电擦除可编程只读存储器,支持按字节擦除和写入操作,具有非易失性,断电后数据不丢失。 常用于存储少量需要频繁更新的数据,如设备配置参数、用户设置等。 NOR FLASH 支持按字节随机访问&…...
对重大保险风险测试的算法理解
今天与同事聊到重大保险风险测试,借助下面链接的文章, 谈IFRS 17下的重大保险风险测试 - 知乎 谈一下对下图这个公式的理解。 尤其是当看到下面这段文字的解释时,感觉有些算法上的东西,需要再澄清一些。 首先,上面文…...
App Cleaner Pro for Mac 中 Mac软件卸载工具
App Cleaner Pro for Mac 中 Mac软件卸载工具 一、介绍 App Cleaner & Uninstaller Pro Mac破解,是一款Mac软件卸载工具,残余垃圾清除工具!可以卸载应用程序或只删除不需要的服务文件,甚至可以删除以前删除的应用程序中的文…...
【操作系统】线程同步:原理、方法与实践
一、线程同步的核心概念 1.1 为什么需要线程同步? 在多线程环境中,当多个线程并发访问共享资源(如内存、文件、数据库等)时,可能会引发数据竞争(Race Condition),导致数据不一致或…...
vue实现二维码生成器和解码器
vue实现二维码生成器和解码器 1.生成基本二维码:根据输入的value生成二维码。 2.可定制尺寸:通过size调整大小。 3.颜色和背景色:设置二维码颜色和背景。 4.静区(quiet zone)支持:通过quietZone调整周围的…...
p2p的发展
PCDN(P2P内容分发网络)行业目前处于快速发展阶段,面临机遇与挑战并存的局面。 一、发展机遇 技术融合推动 边缘计算与5G普及:5G的高带宽、低延迟特性与边缘计算技术结合,显著提升PCDN性能,降低延迟&#x…...
DeepSeek提示词实战大全:提示词合集和使用技巧
大家好,我是大 F,深耕AI算法十余年,互联网大厂技术岗。 知行合一,不写水文,喜欢可关注,分享AI算法干货、技术心得。 更多文章可关注《大模型理论和实战》、《DeepSeek技术解析和实战》,一起探索技术的无限可能! 【数据集篇】更多阅读: 大语言模型常见任务及评测数据集…...
23种设计模式生活化场景,帮助理解
以下是 23种设计模式的生活化场景 及其核心对比,通过日常例子和比喻帮助理解它们的本质区别和应用场景: 创建型模式(5种) 1. 工厂方法(Factory Method) • 场景:快餐店的点餐系统。 • 问题&a…...