关于C++11

news2024/10/7 4:22:31

文章目录

  • 😍C++11优势
  • 😎 列表初始化
  • 😁变量类型推导
    • 👌为什么需要类型推导
    • 👍decltype类型推导(了解)
  • 😜final 与 override
    • final
    • 🤞override
  • ❤️默认成员函数控制
    • 🤩显示缺省函数
    • 😐删除默认函数(禁止调用)
  • 😍右值引用与移动语义
    • 😯什么是左值?什么是左值引用
    • 😹什么是右值?什么是右值引用
    • 😜左值引用与右值引用比较
    • 🎈右值引用使用场景和意义
  • 🧨完美转发
  • 🍕新的类功能
  • 🚕lambda表达式
  • 💕lambda表达式语法
  • 😃可变参数列表(先学会基本特性)
  • 🥱包装器

😍C++11优势

相比C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率。

😎 列表初始化

在C++11中可以直接这样初始化:

内置类型的列表初始化:

int x1 = {10};
int x2{10};//建议使用原来的
int x3 = 1+2;
int x4 = {1+2};
int x5{1+2};
// 数组
int arr1[5] {1,2,3,4,5};
int arr2[]{1,2,3,4,5};
// 动态数组,在C++98中不支持
int* arr3 = new int[5]{1,2,3,4,5};
// 标准容器
vector<int> v{1,2,3,4,5};//这种初始化就很友好,不用push_back一个一个插入
map<int, int> m{{1,1}, {2,2,},{3,3},{4,4}};

自定义类型的列表初始化:

class Point
{
public:
	Point(int x = 0, int y = 0): _x(x), _y(y)
{}
private:
	int _x;
	int _y;
};
int main()
{
	Pointer p = { 1, 2 };
	Pointer p{ 1, 2 };//不建议
return 0;
}

多个对象的列表初始化

多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数即可。
注意:initializer_list是系统自定义的类模板,该类模板中主要有三个方法:begin()、end()迭代器以及获取区间中元素个数的方法size()

class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "66666666666" << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	//C++11容器都实现了带有initializer_list类型参数的构造函数
	vector<Date> vd = { { 2022, 1, 17 }, Date{ 2022, 1, 17 }, { 2022, 1, 17 } };
	return 0;
}


😁变量类型推导

👌为什么需要类型推导

在定义变量时,必须先给出变量的实际类型,编译器才允许定义,
但有些情况下可能不知道需要实际类型怎么给,或者类型写起来特别复杂

int main()
{
	short a = 32670;
	short b = 32670;
	// c如果给成short,会造成数据丢失,如果能够让编译器根据a+b的结果推导c的实际类型,就不会存在问题
	short c = a + b;
	std::map<std::string, std::string> m{ {"apple", "苹果"}, {"banana","香蕉"} };
	
	// 使用迭代器遍历容器, 迭代器类型太繁琐
	std::map<std::string, std::string>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << it->first << " " << it->second << endl;
		++it;
	}
	return 0;
}

C++11中,可以使用auto来根据变量初始化表达式类型推导变量的实际类型,可以给程序的书写提供许多方便。将程序中c与it的类型换成auto,程序可以通过编译,而且更加简洁。

// 使用迭代器遍历容器, 迭代器类型太繁琐   可以使用auto
//std::map<std::string, std::string>::iterator it = m.begin();
auto it = m.begin();

👍decltype类型推导(了解)

为什么需要decltype

**auto使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型。**但有时候可能需要根据表达式运行完成之后结果的类型进行推导,因为编译期间,代码不会运行,此时auto也就无能为力。

decltype是根据表达式的实际类型推演出定义变量时所用的类型,比如
1、推演表达式类型作为变量的定义类型

int a = 10, b = 20;
decltype(a + b)c;
cout << typeid(c).name() << endl;

在这里插入图片描述

  1. 推演函数返回值的类型
    在这里插入图片描述
template<class T1, class T2>
T1 Add(const T1& left, const T2& right)
{
	return left + right;
}
int main()
{
	cout << typeid(Add(1, 2)).name() << endl;
	return 0;
}

😜final 与 override

final

final修饰类的时候,表示该类不能被继承

class A final //表示该类是最后一个类
{
private:
	int _year;
};
class B : public A //无法继承
{

};

final修饰虚函数时,这个虚函数不能被重写

class A 
{
public:
	virtual void fun() final//修饰虚函数
	{
		cout << "this is A" << endl;
	}
private:
	int _year;
};
class B : public A
{
public:
	virtual void fun()//父类虚函数用final修饰,表示最后一个虚函数,无法重写
	{
		cout << "this is B" << endl;
	}
};

🤞override

检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错

class A 
{
public:
	virtual void fun()
	{
		cout << "this is A" << endl;
	}
private:
	int _year;
};
class B : public A
{
public:
	virtual void fun() override
	{
		cout << "this is B" << endl;
	}
};

在这里插入图片描述

❤️默认成员函数控制

在C++中对于空类编译器会生成一些默认的成员函数,比如:构造函数、拷贝构造函数、运算符重载、析构函数和&和const&的重载、移动构造、移动拷贝构造等函数。如果在类中显式定义了,编译器将不会重新生成默认版本。有时候这样的规则可能被忘记,最常见的是声明了带参数的构造函数,必时则需要定义不带参数的版本以实例化无参的对象。而且有时编译器会生成,有时又不生成,容易造成混乱,于是C++11让程序员可以控制是否需要编译器生成。

🤩显示缺省函数

在C++11中,可以在默认函数定义或者声明时加上=default,从而显式的指定编译器生成该函数的默认版本(默认成员函数),用=default修饰的函数称为显式缺省函数。

class A 
{
public:
	A() = default;//让编译器默认生成无参构造函数
	A(int year)    //这样不写缺省值的时候,就不需要自己在去实现一个默认的无参构造函数
		:_year(year)
	{}
	void fun()
	{
		cout << "this is A" << endl;
	}
private:
	int _year;
};

😐删除默认函数(禁止调用)

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置private,并且不给定义,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

class A
{
public:
	A() = default;
	A(int a) : _a(a)
	{}
	//C++11
	// 禁止编译器生成默认的拷贝构造函数以及赋值运算符重载
	A(const A&) = delete;
	A& operator=(const A&) = delete;
private:
	int _a;
	//C++98,设置成private就可以了
	A(const A&) = delete;
	A& operator=(const A&) = delete;
};

😍右值引用与移动语义

传统的C++就有引用,称为左值引用,C++11后,出了右值引用。无论是左值引用还是右值引用,都是给对象取别名(与对象共享一片空间)

😯什么是左值?什么是左值引用

左值是一个表示数据的表达式(如变量名和解引用的指针),**我们可以获取它的地址,也可以对它赋值,左值可以出现在赋值符号的左边,右值不可以出现在左边。**左引用加const修饰,不能对其赋值,但可取地址,是一种特殊情况。左值引用就是给左值取别名。

//以下都是左值
int* p = new int[10];
int a = 10;
const int b = 20;
//对左值的引用
int*& pp = p;
int& pa = a;
const int& rb = b;

左值:
  1、可以取地址
  2、一般情况下可以修改(const修饰时不能修改)


😹什么是右值?什么是右值引用

右值也是一个表示数据的表达式,如:字面常量、表达式返回值、传值返回函数的返回值(不能是左值引用返回)等,右值可以出现在赋值符号的右边,但是不能出现在左边。右值引用就是给右值取别名。

double x = 1.1, y = 2.2;
//常见右值
10;
x + y;
add(1, 2);
//右值引用
int&& rr1 = 10;
double&& rr2 = x + y;
double && rr3 = add(1, 2);
//右值引用一般情况不能引用左值,可使用move将一个左值强制转化为右值引用
int &&rr4 = move(x);
//右值不能出现在左边,错误
10 = 1;
x + y = 1.0;
add(1, 2) = 1;

move:当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。C++11中,std::move()函数位于头文件中,该函数名字具有迷惑性,它并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义。


😜左值引用与右值引用比较

左值引用总结:

1 左值引用只能引用左值,不能引用右值
2.const左值引用既可引用左值,也可引用右值
// 左值引用只能引用左值,不能引用右值
int a = 10;
int& ra1 = a; // ra为a的别名
//int& ra2 = 10; // 编译失败,因为10是右值

//const左值引用既可以引用左值,也可以引用右值
const int& ra3 = 10;
const int& ra4 = a;

右值引用总结:

1.右值引用只能引用右值,一般情况下不能引用左值
2.右值引用可以引用move以后的左值
int a = 10;
int b = 20;
//不能引用左值
//int&& rr1 = a;
int&& rr2 = 10;
int&& rr3 = move(a);//强制转换为右值引用

🎈右值引用使用场景和意义

左值引用既可以引用左值,可以引用右值,为什么C++11还要提出右值引用?因为左值引用存在短板,下面我们来看看这个短板以及右值引用是如何弥补这个短板的!

🧨完美转发

完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数

void Func(int x)
{
	cout << x << endl;
}
template<typename T>
void PerfectForward(T&& t)
{
	Func(t);
}

PerfectForward为转发的模板函数,Func为实际目标函数,但是上述转发还不算完美,完美转发是目标函数总希望将参数按照传递给转发函数的实际类型转给目标函数,而不产生额外的开销,就好像转发者不存在一样。
所谓完美:函数模板在向其他函数传递自身形参时,如果相应实参是左值,它就应该被转发为左值;如果相应实参是右值,它就应该被转发为右值。这样做是为了保留在其他函数针对转发而来的参数的左右值属性进行不同处理(比如参数为左值时实施拷贝语义;参数为右值时实施移动语义)。

我们先来了解万能引用
1、模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。
2、模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力
3、但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值
4、我们希望能够在传递过程中保持它的左值或者右值的属性,就需要用我们下面学习的完美转发

C++11通过forward函数来实现完美转发

void Func(int& x) { cout << "左值引用" << endl; }
void Func(const int& x) { cout << "const 左值引用" << endl; }

void Func(int&& x) { cout << "右值引用" << endl; }
void Func(const int&& x) { cout << "const 右值引用" << endl; }
template<typename T>
void PerfectForward(T&& t)
{
	//Func(t);//没有使用forward保持其右值的属性,退化为左值
	Func(forward<T>(t));
}
int main()
{
	PerfectForward(1);//右值
	int a = 10;
	PerfectForward(a);
	PerfectForward(move(a));

	const int b = 20;
	PerfectForward(b);
	PerfectForward(move(b));
	return 0;
}

右值引用的对象,再作为实参传递时,属性会退化为左值,只能匹配左值引用。使用完美转发,可以保持他的右值属性


🍕新的类功能

默认成员函数
原来C++类中,有6个默认成员函数:
1.构造函数
2.析构函数
3.拷贝构造函数
4.拷贝赋值重载
5.取地址重载
6.const取地址重载

重要的是前4个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。
C++11新增了两个:移动构造函数和移动赋值逸算符重载。
针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:

如果你没有自己实现移动构造函数,且没有实现析构函数、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。

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

如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

C++对于自定义类型成员变量非常的友好,默认成员函数都会恰当处理自定义类型成员


🚕lambda表达式

之前我们要比较自定义类型的一个大小,需要自己实现一个类,并写上仿函数,这样有点复杂。

struct Goods
{
	string _name;
	double _price;
};
struct Compare
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price <= gr._price;
	}
};
int main()
{
	Goods gds[] = { { "苹果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠萝", 1.5} };
	sort(gds, gds+sizeof(gds) / sizeof(gds[0]), Compare());
	return 0;
}

之前自己写的过于复杂,随着lambda的推出,写这种比较大小排序就比较简单了。

int main()
{
	Goods gds[] = { { "苹果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠萝", 1.5} };
	sort(gds, gds + sizeof(gds) / sizeof(gds[0]), [](const Goods& l, const Goods& r)
		->bool
		{
		return l._price < r._price;
		});
	return 0;
}

上面的写法,相当于是把函数直接写到sort的第三个位置上,接下来我们来看一下lambda的语法。


💕lambda表达式语法

lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement }

1.lambda表达式各部分说明

[capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。

(parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略

mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。

->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。

{statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。
注意: 在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。
因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

int main()
{
	[] {};//最简单的lambda表达式上面也不做
	// 省略参数列表和返回值类型,返回值类型由编译器推导为int
	int a = 3, b = 4;
	[=] {return a + 3; };
	
	// 省略了返回值类型,无返回值类型
	//引用传递捕捉a 和 b变量
	auto fun1 = [&](int c) {b = a + c; };
	fun1(10);
	cout << a << " " << b << endl;

	// 各部分都很完善的lambda函数
	//引用方式捕捉b,值传递捕捉其他所有变量
	auto fun2 = [=, &b](int c)->int {return b += a + c; };
	cout << fun2(10) << endl;

	// 值传递捕捉x
	int x = 10;
	auto add_x = [x](int a) mutable { x *= 2; return a + x; };
	cout << add_x(10) << endl;
	return 0;
	return 0;
}

通过上述例子可以看出,lambda表达式实际上可以理解为无名函数,该函数无法直接调用,如果想要直接调用,可借助auto将其赋值给一个变量。

2.捕获列表说明

捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。

[var]:表示值传递方式捕捉变量var

[=]:表示值传递方式捕获所有父作用域中的变量(包括this)

[&var]:表示引用传递捕捉变量var

[&]:表示引用传递捕捉所有父作用域中的变量(包括this)

注意:
a. 父作用域指包含lambda函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量

auto fun1 = [&](int c) {b = a + c; };
fun1(10);
cout << a << " " << b << endl;

c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。 比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复

int x = 10;
auto add_x = [x, =](int a) mutable { x *= 2; return a + x; };
cout << add_x(10) << endl;

d. 在块作用域以外的lambda函数捕捉列表必须为空。
e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。
f. lambda表达式之间不能相互赋值,即使看起来类型相同

class Rate
{
public:
	Rate(double rate): _rate(rate)
	{}
	double operator()(double money, int year)
	{ return money * _rate * year;}
private:
	double _rate;
};
int main()
{
	// 函数对象
	double rate = 0.49;
	Rate r1(rate);
	r1(10000, 2);
	// lamber
	auto r2 = [=](double monty, int year)->double{return monty*rate*year; };
	r2(10000, 2);
	return 0;
}

😃可变参数列表(先学会基本特性)

C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。

//可变参数,你传int,char,还是自定义都会自动给你推导
可以包含0-任意个参数
template<class ...Args>
void ShowList(Args... args)
{
	cout << sizeof...(args) << endl;//计算个数
}
int main()
{
	ShowList(1, 2, 3);
	ShowList(1, 'a');
	ShowList(1, 'A', string("sort"));
	return 0;
}

如果我们要对其取值,如何取?

//需要加上结尾函数

/像套娃
void ShowList()
{
	cout << endl;
}
template <class T, class ...Args>
void ShowList(T value, Args... args)
{
	cout << value << " ";
	ShowList(args...);//不断调用自己,直到最后参数为空,调用上面的结尾函数
}

接下来我们在看看可变参数在列表初始化的应用

template<class ...Args>
void ShowList(Args... args)
{
	int arr[ ] = { args... };//可变参数初始化列表
	cout << endl;
}

我们这里列表初始化内部都是一样的数据,如果我们要传不一样的数据,该如何实现?
C++11,利用逗号表达式调用例外一个函数,最后的0留给数据。

template <class T>
void PrintArg(T t)
{
	cout << t << " ";
}
template <class ...Args>
void ShowList(Args... args)
{
	// 列表初始化
	// {(printarg(args), 0)...}将会展开成((printarg(arg1),0), (printarg(arg2),0), (printarg(arg3),0), etc... )
	int arr[] = { (PrintArg(args), 0)... };
	cout << endl;
}
int main()
{
	ShowList(1, 2, 3);
	ShowList(1, 'a');
	ShowList(1, 'A', string("sort"));
	return 0;
}

也可以给模板函数设置一个返回值

template <class T>
int PrintArg(T t)
{
	cout << t << " ";
	return 0;
}

template <class ...Args>
void ShowList(Args... args)
{
	// 列表初始化 
	//也可以给模板函数设置一个返回值
	int arr[] = { PrintArg(args)... };
	cout << endl;
}

可变参数包结合完美转发的好处:
直接就是普通构造函数的形式,不存在移动构造或者拷贝构造,节省空间

🥱包装器

函数包装器器其实就是函数指针,用了包装器之后,函数模板只会实例化一次,这里我们了解其用法即可。

可调用对象的类型:函数指针、仿函数(函数对象)、lambda

// 函数模板会被实例化多次
template<class F, class T>
T useF(F f, T x)
{
	static int count = 0;
	cout << "count:" << ++count << endl;
	cout << "count:" << &count << endl;

	return f(x);
}

double func(double i)
{
	return i / 2;
}

struct Functor
{
	double operator()(double d)
	{
		return d / 3;
	}
};

int main()
{
	// 函数名
	cout << useF(func, 11.11) << endl;

	// 函数对象
	cout << useF(Functor(), 11.11) << endl;

	// lamber表达式
	cout << useF([](double d)->double{ return d / 4; }, 11.11) << endl;

	return 0;
}

在这里插入图片描述

这里我们可以看到静态变量count,每次的地址都不一样,说明函数模板实例化了3次。

我们可以通过包装器只让函数模板实例化一次

int main()
{	
	// 函数名 生成一个函数包装器,f1就是函数指针 ==  double (*f1)(double)
	std::function<double(double)> f1 = func;
	cout << useF(f1, 11.11) << endl;

	// 函数对象
	std::function<double(double)> f2 = Functor();
	cout << useF(f2, 11.11) << endl;

	// lamber表达式
	std::function<double(double)> f3 = [](double d)->double{ return d / 4; };
	cout << useF(f3, 11.11) << endl;

	return 0;
}

在这里插入图片描述

可以看到count的值是累加的,说明函数模板只实例化了一次

std::function包装各种可调用的对象,统一可调用对象类型,并且指定了参数和返回值类型。
为什么有std:function,因为不包装前可调用类型存在很多问题:
1、函数指针类型太复杂,不方便使用和理解
2、仿函数类型是一个类名,没有指定调用参数和返回值。得去看operator()的实现才能看出来。3、lambda表达式在语法层,看不到类型。底层有类型,基本都是lambda_uuid,也很难看

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/73564.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TH10-数据统计与内容审核

TH10-数据统计与内容审核1、用户冻结解冻1.1 用户冻结ManageControllerManageService1.2 用户解冻ManageControllerManageService1.3 查询数据列表UserInfoManageService1.4 探花系统修改UserFreezeService2、数据统计2.1 数据采集2.1.1 部署RabbitMQ2.1.2 消息类型说明2.1.3 实…

使用dd+hexdump命令修改环境变量的值和升级uboot

前言 这篇写的较细&#xff0c;使用dd擦除emmc本来就是比较危险的事情&#xff0c;所以一定要细致。哪里没看明白的&#xff0c;赶紧留言问我&#xff0c;可不能存有侥幸心理。 思路大概就是&#xff1a; 1 先从emmc把数据读出来&#xff0c;放一个镜像文件里&#xff0c;使…

【整理】Python全栈技术学习路线

【整理】Python全栈技术学习路线【阶段一】Python基础Linux【阶段二】多任务编程服务器前端基础【阶段三】数据库mini Web框架【阶段四】Dhango框架美多商城项目【阶段五】DRF框架美多商城后台【阶段六】项目部署Flask框架Hm头条【阶段七】人工智能基础推荐系统基础Hm头条推荐系…

带你了解extern “C“

1.extern “C” 这个语法是c的语法。我们知道在一个.c文件中调用另一个.c中实现的函数是没有任何问题的&#xff0c;一个.cpp文件调用另一个.cpp文件中实现的函数也是没有问题的。但是我们如果想要在一个.cpp文件调用另一个.c文件中实现的函数&#xff0c;或者在一个.c文件中调…

双调序列

目录 双调序列 思路: 代码: 时间复杂度: 总结: 题目链接: 双调序列 题目描述&#xff1a; XJ编程小组的童鞋们经常玩一些智力小游戏&#xff0c;某月某日&#xff0c;小朋友们又发明了一种新的序列&#xff1a;双调序列&#xff0c;所谓的双调呢主要是满足如下条件描述…

TensorFlow之分类模型-2

1 基本概念 2 文本分类与情感分析 获取数据集 加载数据集 训练数据集 性能设置 为了提升训练过程中数据处理的性能&#xff0c;keras技术框架提供数据集缓存的功能&#xff0c;使用缓存可以避免读取磁盘数据集时由于IO消耗太多而出现性能瓶颈的问题&#xff0c;如果数据集…

操作系统的主要功能是什么

操作系统的主要功能是进程管理、存储管理、设备管理、文件管理、作业管理。 计算机系统的资源可分为设备资源和信息资源两大类。 操作系统位于底层硬件与用户之间&#xff0c;是两者沟通的桥梁。 1、进程管理&#xff0c;其工作主要是进程调度&#xff0c;在单用户单任务的情…

opcj2-盘点几个常见的Java开源脚手架

很多人抱怨自己是CURDer&#xff0c;很多时候就是在简单的修修改改。如果不书序SSM&#xff08;Spring、SpringMVC和Mybatis&#xff09;套路的人可能开始的时候会感觉非常吃力。但是熟悉之后发现其实就这么回事。SpringMVC负责响应对外接口&#xff0c;Mybatis负责数据库的访问…

TF4-圈子功能

TF4-圈子功能1、首页推荐1.1、接口分析1.2、功能实现1.2.1 controller1.2.2 service1.2.3 API接口1.2.4 请求dto对象2、MongoDB集群3、圈子功能2.1、功能说明1.2、实现方案分析1.3、技术方案(重点)1.4、表结构设计4、圈子实现3.1、环境搭建3.1.1、mongo主键自增3.1.2、实体类Mo…

基于matlab的SVM支持向量机分类仿真,核函数采用RBF函数

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 支持向量机&#xff08;support vector machines, SVM&#xff09;是二分类算法&#xff0c;所谓二分类即把具有多个特性&#xff08;属性&#xff09;的数据分为两类&#xff0c;目前主流机器学…

如何清理 docker 磁盘空间 附讲解(全)

目录前言1. Docker System 命令1.1 docker system df1.2 docker system prune2. 冗余容器或镜像3. 限制容器日志前言 补充docker知识点&#xff0c;可看我之前的文章&#xff1a;Docker零基础从入门到精通&#xff08;全&#xff09; docker 镜像特别容易占空间&#xff0c;稍…

基于Redis实现高性能延时消息队列

最近在倒腾自建博客后端系统&#xff0c;需要用到延时任务的功能&#xff0c;但手头只有一套MySQL和Redis&#xff0c;如果搞一套MQ成本有点大&#xff0c;于是想着用redis实现延时消息队列。有些场景用数据库的定时扫表也能简单实现延时消息的功能&#xff0c;不过对于我这边的…

Bitmap,布隆过滤器初步了解

布隆过滤器使用教程 文章目录布隆过滤器使用教程1.背景2.什么是Bitmap3.布隆过滤器3.1 什么是布隆过滤器3.2 布隆过滤器的作用3.3 布隆过滤器的基本原理4.布隆过滤器的实现Guava和Redisson4.1 实现思路4.2 SpringBoot实现这些操作Bitmap,guava,redisson布隆过滤器1.背景 最近公…

redis知识点汇总

一、Redis的数据类型和数据结构 1、Redis五种数据类型 String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Hash&#xff08;哈希&#xff09;、Set&#xff08;集合&#xff09;和Sorted Set&#xff08;有序集合&#xff09;。 2、Redis的底层数据…

C# 数据类型分值类型及引用类型

一 程序中的变量与常量 程序的基本任务是&#xff1a;对数据进行处理&#xff1b; 数据分为变量(variable)与常量(literal) int age18; 变量是值可以改变&#xff0c;本质上是内存的空间&#xff0c;用来存储信息 常量的值是固定的&#xff0c;直接写出来的&#xff0c;称字面…

点击按钮,下载文件

实现文件的下载功能 1、使用a标签 直接下载仅适用于浏览器无法识别的文件。 如果是浏览器支持的文件格式&#xff0c;如html、jpg、png、pdf等&#xff0c;则不会触发文件下载&#xff0c;而是直接被浏览器解析并展示 <ahref"http://xxxxxx.rar"download>下载…

vue中的性能优化

文章目录一、Vue为什么要做性能优化二、如何做vue的性能优化1. 网络请求优化link标签项目静态资源压缩懒加载利用浏览器的缓存机制高效复用项目文件总结2. 代码优化3. 用户体验优化场景1场景2一、Vue为什么要做性能优化 性能优化的目的是使网站的加载速度更快&#xff0c;用户…

【语音处理】基于自适应差分脉冲编码调制(ADPCM)的实现研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步进步&#xff0c;matlab项目目标合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信息&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算…

音视频直播系统之 WebRTC 中的协议UDP、TCP、RTP、RTCP详解

一、UDP/TCP 如果让你自己开发一套实时互动直播系统&#xff0c;在选择网络传输协议时&#xff0c;你会选择使用UDP协议还是TCP协议 假如使用 TCP 会怎样呢&#xff1f;在极端网络情况下&#xff0c;TCP 为了传输的可靠性&#xff0c;将会进行反复重发信息的操作 在 TCP 协议…

Nagios篇之Nagios服务关联飞书实现消息告警

一、前言 通常情况下&#xff0c;我们在利用Nagios监控来做服务器监控时&#xff0c;告警是必不可少的&#xff0c;以便于运维人员能够及时发现异常&#xff0c;进而处理问题&#xff0c;所以关联Nagios就变得极为重要。 Nagios关联告警的形式很多&#xff0c;可以进行短信推送…