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

了解c++11中的新增

一,统一的初始化列表

在引入c++11后,我们得出计划都可以用初始化列表进行初始化。

C++11 扩大了用大括号括起的列表 ( 初始化列表 ) 的使用范围,使其可用于所有的内置类型和用户自
定义的类型, 使用初始化列表时,可添加等号 (=) ,也可不添加

int  main()
{int i = 0;int j = { 0 };int k{ 0 };int l(0);//如日期类return 0;
}//对象的初始化
struct Point{int _x;int _y;};int main(){int array1[] = { 1, 2, 3, 4, 5 };int array2[5] = { 0 };Point p = { 1, 2 };return 0;}//日期类对象的初始化
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;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2022, 1, 1); // old style// C++11支持的列表初始化,这里会调用构造函数初始化Date d2{ 2022, 1, 2 };Date d3 = { 2022, 1, 3 };//这里的本质就是,以该参数构造对象再拷贝给给这里的对象Date* d4 = new Date[3]{ {2023,5,3}, {2022, 1, 3},{2023,1,2} };return 0;
}

数组与链表的初始化

int main()
{vector<int> v = { 1,2,3,4,5,6 };list<string> l = { "hello","world" };return 0;
}

并且再c++11引入了std::initializer_list ,一种特殊的构造方式:

initiallizer_list

initializer_list是C++11提供的新类型,定义在头文件中。 用于表示某种特定类型的值的数组,和vector一样,initializer_list也是一种模板类型。即一组数据的类型。

一般它的作用也就是为了支持容器的参数列表的构造。

如下:通过typeid我们来查看il的类型,

库中的定义: 

 

 库中实现了三个成员函数,分别是首尾和大小。我们不难看出这肯定是实现了迭代器,也确实是这样样,他的迭代器就是他的原生指针。

int main()
{auto il = { 1,2,3,4,5 };cout << typeid(il).name()<<endl;auto it = il.begin();while (it != il.end()){cout << *it;it++;}cout << endl;for (auto it : il){cout << it;}return 0;
}

 对于initailizer_list,不仅仅是一般的类型的数据的和,对于vector,list,map,set等构造都支持参数列表(nitailizer_list)这样的初始化:

int main()
{pair<string, string> kv = { "希尔排序","1" };map<string, string> p = { kv,{"冒泡排序","2"},{"快速排序","3"}};//初始化map时,除了用pair,我们这里也可以用initializer_list  ->实际上回隐式类型转换为pairfor(auto &it:p){cout << it.first<<" "<<it.second<< endl;}return 0;
}

 二,声明

auto

C++98 auto 是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局
部的变量默认就是自动存储类型,所以 auto 就没什么价值了。 C++11 中废弃 auto 原来的用法,将
其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初
始化值的类型。

自动类型推导,更加简便的声明。实际当中,我们一般范围for用,

decltype

关键字 decltype 将变量的类型声明为表达式指定的类型。
int main()
{//对于类型推导 我们知道typidint i = 10;double j = 10.2;cout << typeid(i).name() << endl;cout << typeid(j).name() << endl;//获取类型的字符串 但不能当作类型去定义 //我们平时需要定义时就用auto定义,但若我们的模板参数需要这个类型如何取到这个类型//利用关键字decltype 获取数据类型vector<decltype(j)> v;v.push_back(1);v.push_back(2);for (int i = 0; i < v.size(); i++){cout << v[i]<<" ";}decltype(j) data;//可以当作类型用定义return 0;}

三,范围for

就是迭代器基础实现的遍历,写起来更加方便,我们差不多已经都熟练使用。

四,智能指针

智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。

五,c++11种STL库中的变化

  新容器:forward_list(单链表),arry(静态数组),两个哈希表封装的无序关联容器unordered_map,unordered_set。

实际应用中,arry没谁用,我们有vetor,单链表意义也不大,虽然节省空间,但对于尾删效率太低下了,较有大用处的是者两个无序容器.

六,右值引用与移动语义(重要)

什么是左值,什么是右值?

传统的 C++ 语法中就有引用的语法,而 C++11 中新增了的右值引用语法特性。
我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名
什么是左值?左值引用?
左值是一个表示数据的表达式(如变量名或解引用的指针) 我们可以获取它的地址 + 可以对它赋
值, 左值可以出现赋值符号的左边,右值不能出现在赋值符号左边 。定义时 const 修饰符后的左
值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。
int main()
{//下面三个变量都是左值     我们可以给它赋值,主要看他是否可以取地址int* p = new int(1);int b = 0;const int c = 10;//i还是左值int i = 0;int j = i;}

什么是右值?右值引用?
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值 ( 这个不能是左值引
用返回 ) 等等, 右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边, 右值不能
取地址 。右值引用就是对右值的引用,给右值取别名。
int main()
{int i = 0, j = 0;//如下都是右值  右值可以是表达式,返回值,右值无法取地址10;i + j;fmin(i , j);//之前的引用都是左值引用,我们来看看右值引用int&& r = 10;double &&r1= i + j;int&& min = fmin(i, j);}

左值引用不能直接给给右值取别名,需要const。右值引用也不能直接给左值引用,这里可以move后引用。

int main()
{//左值引用给右值取别名,不能直接引用,右值不能被修改,因此需要constconst int& i = 10;int&& j = 10;//右值引用右值int&& m = i + j;//右值引用引用左值     不能直接引用,还是需要转化类型   //右值引用可以给move后的左值引用int p = 10; int q = 10;int&& r = move(q);int&& n = (const int) q;}

引入右值引用与左值引用的效果一样,减少大量拷贝。

那么右值引用是如何使用的?

右值引用的场景

因为在函数的返回值中,如果要对函数返回的值引用,则必须要满足,在函数的声明周期结束后,值的生命周期还在,否则就无法使用引用。

那我们想要返回该如何?比如说我们自己实现string里面的tostring:
//那么如何实现这里的ret返回引用呢?
string tostring(int x)
{string ret;while (x){int val = x % 10;x = x / 10;ret += (val + '0');}reverse(ret.begin(),ret.end());return ret;
}

在正常引用函数的返回值肯定不行。

首先函数返回值是一个右值,我们需要使用右值引用,其次右值引用还是要考虑到该问题,函数调用完毕,释放函数栈帧时,对应的返回值的生命周期也结束了,此时引用,引用的就是个空。
首先在c++中,右值分为纯右值与将亡值(自定义的右值)。
首先对于正常的返回,不调用引用,过程是这样的:

首先ret在这里会调用三次深拷贝,代价太大,那么有无优化的方案?

 对于这里的ret,还是传值返回,但是在即将销毁时,我们可以将它识别是一个将亡值(右值),对于将亡值,我们拷贝构造时,使用右值引用传参(移动拷贝),直接把资源转移过来,不再进行深度拷贝,但是在进入main函数中的拷贝之后,赋值是不支持右值对象的,因此这里还需要实现右值赋值。

amespace myspace
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string tostring(int x){string ret;while (x){int val = x % 10;x = x / 10;ret += (val + '0');}return ret;}string(const char* str = ""):_size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}void swap(string& s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}// 拷贝构造string(const string& s):_str(nullptr){cout << "string(const string& s) -- 深拷贝" << endl;string tmp(s._str);swap(tmp);}// 赋值重载string& operator=(const string& s){cout << "string& operator=(string s) -- 深拷贝" << endl;string tmp(s);swap(tmp);return *this;}// 移动构造  右值引用string(string&& s):_str(nullptr), _size(0), _capacity(0){cout << "string(string&& s) -- 移动语义" << endl;swap(s);}// 移动赋值  右值引用string& operator=(string&& s){cout << "string& operator=(string&& s) -- 移动语义" << endl;swap(s);return *this;}~string(){delete[] _str;_str = nullptr;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size >= _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}//string operator+=(char ch)string& operator+=(char ch){push_back(ch);return *this;}const char* c_str() const{return _str;}private:char* _str;size_t _size;size_t _capacity; // 不包含最后做标识的\0};
}

通过右值引用我们减掉了深度拷贝的代价。这里我们一般还可以通过调试查看函数调用信息,

对于将亡值,我们一般使用move将一个左值转化为将亡值。自定义的右值一般也是将亡值。

仔细看的话,用过右值引用,我们还将他的生命周期延长了,我们通过右值引用使得这份资源还在。

当然我这里的右值引用,移动构造对于深拷贝就能发挥它的作用,浅拷贝的自定义类型没什么用。

注意:注意move移动语义,本是是不会改变这个值的属性,而是调用后的返回值的类型发生了改变。

其次对于一个右值的引用之后它的属性是一个左值,因为右值不能被修改,但是右值的右值引用可以被修改,否则无法实现移动构造,与移动复制。

库中的一些应用

 除了返回值可以被引用外,移动构造与移动拷贝相对于左值的拷贝构造,赋值。更加的快速和节省空间,因为我们这里直接是引用。

通过右值引用实现了返回值的引用,以这种方式许多场景下的应用就可以实现了。

c+11后,我们通过转化为右值,使用移动构造,移动拷贝,效率就会高许多。

STL容器在c++11后,都增加了移动构造与移动赋值。

vector的构造与赋值

 

list的构造与赋值

以及push操作也基本添加了右值版本:

万能引用

c++11在提供右值及右值引用后,还增加了万能引用。

所谓的万能引用,就是模板参数的引用,这里用的是&&,但不代表是右值引用。

格式如下:

template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}

通过万能引用,是左值就调左值引用,是右值就调右值引用。但是还是要记住一点,右值被右值引用之后,属性是左值,因此在处理右值传参用右值对应的接口,我们都需要吧接口里的值的类型在move一下。

注意事项:

针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:
如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类
型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,
如果实现了就调用移动构造,没有实现就调用拷贝构造。
如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中
的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内
置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋
值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。 ( 默认移动赋值跟上面移动构造
完全类似 )
如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

七.defalut与delete

强制生成默认函数的关键字default,;取消生成默认函数的关键字delete:
C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原
因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以
使用default关键字显示指定移动构造生成。 当然我们也可以取消不让这些函数生成。

八,模板的可变参数

首先我们知道函数的参数可以是可变参数,c++11对模板也引入了可变参数。

这里的参数,我们叫可变参数包,

template<class ...Args> //模板的可变参数包
void show(Args...arg)
{//可以包含任意多个类型的参数
}
STL容器中的 empalce相关接口函数:就是可变参数
emplace 系列的接口,支持模板的可变参数,并且也可以万能引用。
以vector为例,在c++11当中增加了两个家口,emplace与emplace_back,这两个接口都是用来
插入的,emplace_back尾插,那么这两个插入与insert有什么区别呢?
首先就是可变参数,emplace会根据参数将Args作为构造函数的参数构造出一个该元素,然后插入其中。
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector = {10,20,30};myvector.emplace_back (100);myvector.emplace_back (200);std::cout << "myvector contains:";for (auto& x: myvector)std::cout << ' ' << x;std::cout << '\n';return 0;
}//运行结果  myvector contains: 10 20 30 100 200

在引入移动构造与构造时,insert就是先构造,在移动构造插入,而对于emplace是直接构造插入。对于大一点的浅拷贝的自定义类型,emplace相对于会更好一点。

九,lambda表达式

在c++98之前,比如我们在用sort进行排序时,我们是传一个仿函数,且该种排序只能支持库里提供的类型,另外的类型就需要我们重写一个仿函数传进去。

操了c++11,虽然问题得到了解决,但是人们认为这样写还是太过麻烦,比如每次传参进去的仿函数都必须以它如何排序的方式进行命名,因为具体实现的比较我们是看不到的,因此借鉴了python的lambda表达式,实现更加方便,更加清晰的比较。

lambda表达式的构成:

lambda 表达式书写格式: [capture-list] (parameters) mutable -> return-type { statement
}
lambda 表达式各部分说明:
[capture-list] : 捕捉列表 ,该列表总是出现在 lambda 函数的开始位置, 编译器根据 []
判断接下来的代码是否为 lambda 函数 捕捉列表能够捕捉上下文中的变量供 lambda
函数使用
(parameters) :参数列表。与 普通函数的参数列表一致 ,如果不需要参数传递,则可以
连同 () 一起省略。
mutable :默认情况下, lambda 函数总是一个 const 函数, mutable 可以取消其常量
性。使用该修饰符时,参数列表不可省略 ( 即使参数为空 ) 。---不需要一般可以忽略不写
->returntype :返回值类型 。用 追踪返回类型形式声明函数的返回值类型 ,没有返回
值时此部分可省略。 返回值类型明确情况下,也可省略,由编译器对返回类型进行推
{statement} :函数体 。在该函数体内,除了可以使用其参数外,还可以使用所有捕获
到的变量。

事实上lalmbda本质就是一个函数对象,我们一般这样去使用它:

int main()
{//比如简单写一个打印出入的参数
auto it=	[]       (int x)    ->int   { cout << x; return 0; };//捕捉列表  参数列表  返回类型   函数体//我们一般用auto自定推导类型来获取这个对象it(1);//对象传参
//当然我们也可以省略返回值类型,它可以自动推导
//auto it=[](int x){ cout << x; return 0; };return 0;
}

 那么我们就可以用lambda去替换仿函数。

现在我们就可以用lambda表达式去实现仿函数一样的功能:

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());//lambda//这里的lambda可以理解为匿名函数对象sort(v.begin(), v.end(), [](Goods &it1,  Goods& it2) {return it1._price > it2._price; });sort(v.begin(), v.end(), [](Goods &it1, Goods& it2) {return it1._price < it2._price; });return 0;
}

因为sort函数提供的是模板(对于比较这一部分),因此我们只要传参可调用的对象就可以。

那么有人就开始疑惑了,lambda返回类型到底是一个什么?通过typeid我们可以看看:

int main()
{auto p=[](Goods& it1, Goods& it2) {return it1._price > it2._price; };auto q = [](Goods& it1, Goods& it2) {return it1._price > it2._price; };cout << typeid(p).name()<<endl;cout << typeid(q).name()<<endl;
}

 实际上是一个类,每个lambda都有自己对应的类。

关于捕捉列表,lambda表的是其他构成我们能理解,但对于捕捉列表是什么呢?

所谓的捕捉,就是可以将父作用域里的变量直接拿来使用,但传值过来的变量无法被修改。

除了传值,也可以传引用捕捉,但在书写方面与取地址写法一样,注意别混淆。

传值就是普通函数传参,传引就是引用传参。如果想捕捉地址,就实现把地址取出来。

当然捕捉引用时,它自动传参时,此时就不再使用mutable了。

即:

int x = 1; int y = 2;//不捕获时auto q = [](int x, int y)->void{int temp = x;x = y;y = temp;};q(x, y);//这里只是作为参数传递过去,形参的改变不影响实参cout<<x<<" " << y << endl;//捕获时,但注意,这里虽然捕获了,可以直接用//但此时默认情况下这里的函数是不能修改的,需要加入mutable表示可修改auto p = [x, y]()mutable-> void {int temp = x;x = y;y = temp;};p();//这里只是作为参数传递过去,形参的改变不影响实参cout << x << " " << y << endl;auto n = [&x, &y]()-> void{int temp = x;x = y;y = temp;};n();//这里是传引用,因此会完成交换cout << x << " " << y << endl;

lambda的原理也是仿函数。

十,包装器

function

有了仿函数,lambda,实际上还有函数指针,这三个本质其实都一样,都是一个函数,可以被其他对象调用去实现某个功能。因为除了函数指针和仿函数还能传,lanmbda的类型我们是不得而知的,需要function去将这些包装,我们能直接获取其类型。

因此在c++11中又提出一个概念包装器,就是跟适配器一样。

我们之前学习单链表,栈和队列等就是用vector,list去适配出这样的一个结构。

而这里的包装器,就是用函数指针,或者lambda,仿函数去适配(包装)我们所需要的一个“函数对象”,去被调用。

语法:class function

std::function 在头文件 < functional >
// 类模板原型如下
template < class T > function ;     
template < class Ret , class ... Args >
class function < Ret ( Args ...) > ;
模板参数说明:
Ret : 被调用函数的返回类型
Args… :被调用函数的形参

 function的本质就是一个类模板,适配就是去适配 仿函数,函数指针,lambda的其中一个。

//包装器 function
//我们还是以交换两个整数为例
//仿函数
struct Swap1
{void operator()(int& x, int& y){int temp = x;x = y;y = temp;}
};
//函数
void Swap2(int& x,int& y)
{int temp = x;x = y;y = temp;
}
//lambda
auto Swap3 = [](int& x, int& y)->void {int temp = x; x = y; y = temp; };
//首先我们先来使用一下
int main()
{int x = 1; int y = 2;//可以包装这三个function<void(int&, int&)> p1 = Swap1();p1(x, y);cout << x << " " << y << endl;function<void(int&, int&)> p2 = Swap2;p2(x, y);cout << x << " " << y << endl;function<void(int&, int&)> p3 = Swap3;p3(x, y);cout << x << " " << y << endl;//通过function模板 ,在传入参数时,我们就可以选择三个其中之一进行传参map<string, function<void(int&, int&)> >  op = { {"仿函数", Swap1()},{"函数指针", Swap2},{"lambda", Swap3} };/*m.insert(make_pair("仿函数", Swap1()));m.insert(make_pair("函数指针", Swap2));m.insert(make_pair("仿函数", Swap3));*///map<string, function<void(int&, int&)> >  m = { {"仿函数", p1},{"函数指针", p2},{"仿函数", p3} };op["仿函数"](x, y); op["函数指针"](x, y);op["lambda"](x, y);}

当然这里我们的函数的参数类型是一样的。

包装成员函数

在包装成员函数时,我们需要注意几点:

1.指定类域

2.要在成员函数前加&符号,才表示成员函数的地址

3.传参需要加入他的地址

class Func
{
public:static int Add1(int x, int y){return x + y;}double Add2(double  x, double  y){return x + y;}
};
int main()
{//如果是static,我们可以直接包装function<int(int, int)> p1 = Func::Add1;cout << p1(1, 2)<<endl;//如果是普通成员函数,则还需要一个对象指针Func a;function<double(Func*, double, double)> p2 = &Func::Add2;cout << p2(&a, 1.1, 2.1) << endl;//对象也可以function<double(Func a, double, double)> p3 = &Func::Add2;Func b;cout << p3(b,1.2, 2.3) << endl;
}

bind

除了function,还有第二个包装器bind:

std::bind 函数定义在头文件中, 是一个函数模板,它就像一个函数包装器 ( 适配器 ) 接受一个可
调用对象( callable object ),生成一个新的可调用对象来 适应 原对象的参数列表 。一般而
言,我们用它可以把一个原本接收 N 个参数的函数 fn 通过绑定一些参数,返回一个接收M个(M
可以大于N,但这么做没什么意义)参数的新函数 。同时,使用 std::bind 函数还可以实现参数顺
序调整等操作。
// 原型如下:
template < class Fn , class ... Args >
/* unspecified */ bind ( Fn && fn , Args && ... args );
// with return type (2)
template < class Ret , class Fn , class ... Args >
/* unspecified */ bind ( Fn && fn , Args && ... args )

 可以用来调整参数的位置,

int main()
{//表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定std::function<int(int, int)> func1 = std::bind(Plus, placeholders::_1, placeholders::_2);//表示绑定函数 plus 的第一,二为: 1, 2auto  func2 = std::bind(Plus, 1, 2);   cout << func1(1, 2) << endl;cout << func2() << endl;
}

相关文章:

了解c++11中的新增

一&#xff0c;统一的初始化列表 在引入c11后&#xff0c;我们得出计划都可以用初始化列表进行初始化。 C11 扩大了用大括号括起的列表 ( 初始化列表 ) 的使用范围&#xff0c;使其可用于所有的内置类型和用户自 定义的类型&#xff0c; 使用初始化列表时&#xff0c;可添加等…...

104. 二叉树的最大深度(Java)

目录 解法&#xff1a; 官方解答&#xff1a; 方法一&#xff1a;深度优先搜索 方法二&#xff1a;广度优先搜索 思路与算法 复杂度分析 时间复杂度&#xff1a; 空间复杂度&#xff1a; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根…...

SpringSecurity6 | 自定义认证规则

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…...

浅析安科瑞电动机保护器在广州某地铁项目的设计与应用-安科瑞 蒋静

1 摘要 随着城市的发展&#xff0c;较多城市的轨道交通选择修建地下式车辆段&#xff08;或停车场&#xff09;&#xff0c;即车辆段&#xff08;或停车场&#xff09;位于地下或设置有上盖&#xff08;上盖上再做物业开发&#xff09;。为了给工作人员提供良好的工作环境、给…...

LeetCode 2048. 下一个更大的数值平衡数

【LetMeFly】2048.下一个更大的数值平衡数 力扣题目链接&#xff1a;https://leetcode.cn/problems/next-greater-numerically-balanced-number/ 如果整数 x 满足&#xff1a;对于每个数位 d &#xff0c;这个数位 恰好 在 x 中出现 d 次。那么整数 x 就是一个 数值平衡数 。…...

多线程(初阶七:阻塞队列和生产者消费者模型)

目录 一、阻塞队列的简单介绍 二、生产者消费者模型 1、举个栗子&#xff1a; 2、引入生产者消费者模型的意义&#xff1a; &#xff08;1&#xff09;解耦合 &#xff08;2&#xff09;削峰填谷 三、模拟实现阻塞队列 1、阻塞队列的简单介绍 2、实现阻塞队列 &#…...

区间价值 --- 题解--动态规划

目录 区间价值 题目描述 输入描述: 输出描述: 输入 输出 备注: 思路&#xff1a; 代码&#xff1a; 区间价值 J-区间价值_牛客竞赛动态规划专题班习题课 (nowcoder.com) 时间限制&#xff1a;C/C 2秒&#xff0c;其他语言4秒 空间限制&#xff1a;C/C 262144K&…...

计算机毕业设计 基于大数据的心脏病患者数据分析管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

20:kotlin 类和对象 --泛型(Generics)

类可以有类型参数 class Box<T>(t: T) {var value t }要创建类实例&#xff0c;需提供类型参数 val box: Box<Int> Box<Int>(1)如果类型可以被推断出来&#xff0c;可以省略 val box Box(1)通配符 在JAVA泛型中有通配符?、? extends E、? super E&…...

我对迁移学习的一点理解(系列2)

文章目录 我对迁移学习的一点理解 我对迁移学习的一点理解 源域和目标域是相对的概念&#xff0c;指的是在迁移学习任务中涉及到的两个不同的数据集或领域。 源域&#xff08;Source Domain&#xff09;通常指的是已经进行过训练和学习的数据集&#xff0c;它被用来提取特征、…...

Spring MVC学习随笔-控制器(Controller)开发详解:控制器跳转与作用域(二)视图模板、静态资源访问

学习视频&#xff1a;孙哥说SpringMVC&#xff1a;结合Thymeleaf&#xff0c;重塑你的MVC世界&#xff01;&#xff5c;前所未有的Web开发探索之旅 衔接上文Spring MVC学习随笔-控制器(Controller)开发详解&#xff1a;控制器跳转与作用域&#xff08;一&#xff09; SpingMVC中…...

原型模式(Prototype Pattern)

1 基本概念 1.1 大佬文章 设计模式是什么鬼&#xff08;原型&#xff09; 详解设计模式&#xff1a;原型模式-腾讯云开发者社区-腾讯云 1.2 知识汇总 &#xff08;1&#xff09;原型模式&#xff1a;先 new 一个实例&#xff0c;该实例符合需求&#xff0c;之后再根据这个实…...

IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

文章目录 1. 引言2. 短轮询&#xff08;Short Polling&#xff09;2.1 原理2.2 代码示例2.2.1 服务器端&#xff08;Node.js&#xff09;2.2.2 客户端&#xff08;HTML JavaScript&#xff09; 3. 长轮询&#xff08;Long Polling&#xff09;3.1 原理3.2 代码示例3.2.1 服务器…...

04_W5500_TCP_Server

上一节我们完成了TCP_Client实验&#xff0c;这节使用W5500作为服务端与TCP客户端进行通信。 目录 1.W5500服务端要做的&#xff1a; 2.代码分析&#xff1a; 3.测试&#xff1a; 1.W5500服务端要做的&#xff1a; 服务端只需要打开socket&#xff0c;然后监听端口即可。 2…...

入门Redis学习总结

记录之前刚学习Redis 的笔记&#xff0c; 主要包括Redis的基本数据结构、Redis 发布订阅机制、Redis 事务、Redis 服务器相关及采用Spring Boot 集成Redis 实现增删改查基本功能 一&#xff1a;常用命令及数据结构 1.Redis 键(key) # 设置key和value 127.0.0.1:6379> set …...

SpringSecurity6 | 自定义登录页面

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…...

从单向链表中删除指定值的节点

输入一个单向链表和一个节点的值&#xff0c;从单向链表中删除等于该值的节点&#xff0c;删除后如果链表中无节点则返回空指针。 链表的值不能重复。构造过程&#xff0c;例如输入一行数据为:6 2 1 2 3 2 5 1 4 5 7 2 2则第一个参数6表示输入总共6个节点&#xff0c;第二个参数…...

Vue2与Vue3的语法对比

Vue2与Vue3的语法对比 Vue.js是一款流行的JavaScript框架&#xff0c;通过它可以更加轻松地构建Web用户界面。随着Vue.js的不断发展&#xff0c;Vue2的语法已经在很多应用中得到了广泛应用。而Vue3于2020年正式发布&#xff0c;带来了许多新的特性和改进&#xff0c;同时也带来…...

实时动作识别学习笔记

目录 yowo v2 yowof 判断是在干什么,不能获取细节信息 yowo v2 https://github.com/yjh0410/YOWOv2/blob/master/README_CN.md ModelClipmAPFPSweightYOWOv2-Nano1612.640ckptYOWOv2-Tiny...

5G常用简称

名称缩写全称非周期 信道状态信息参考信号aperidoc CSIAperidoc Channel State Information缓冲区状态报告BSRBuffer Status Report小区特定无线网络标识CS-RNTICell-Specific Radio Network Temporary Identifier主小区组MCGMaster Cell groupMCG的节点MNMasternode主小区PCel…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...