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

C++之模板

本阶段主要针对C++泛型编程ST技术做详细讲解,探讨C++更深层的使用

1.1 模板的概念

模板就是建立通用的模具,大大提高复用性

模板的特点:

模板不可以直接使用,它只是一个框架

模板的通用并不是万能的 

1.2 函数模板

C++另一种编程思想称为 泛型编程,主要利用的技术就是模板

C++提供两种模板机制:函数模板和类模板

1.2.1 函数模板语法

函数模板作用:

建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表,

语法:

template<typename T>函数声明或定义

解释:

template--- 声明创建模板

typename---表面其后面的符号是一种数据类型,可以用class代替

T ---通用的数据类型,名称可以替换,通常为大写字母

示例:

#include<iostream>
using namespace std;template<typename T>>//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用的数据类型
void myswap(T &a,T &b)
{T temp = a;a = b;b = temp;
}void test01()
{int a = 10;int b = 20;//1,自动类型推导cout << "第一次交换:自动类型推导" << endl;myswap(a, b);cout << "a=" << a << endl;cout << "b=" << b << endl;//2,显示指定类型cout << "第二次交换:显示指定类型" << endl;myswap<int>(a, b);cout << "a=" << a << endl;cout << "b=" << b << endl;}int main()
{test01();system("pause");return 0;
}

 

总结:

函数模板利用关键字 template

使用函数模板有两种方式:自动类型推导、显示指定类型

模板的目的是为了提高复用性,将类型参数化 

1.2.2 函数模板注意事项

注意事项:
自动类型推导,必须推导出
一致的数据类型T,才可以使用
模板必须要确定出T的数据类型,才可以使用

示例:

#include<iostream>
using namespace std;template<typename T>//typename可以替换成class
void myswap(T& a, T& b)
{T temp = a;a = b;b = temp;
}void test01()
{int a = 10;int b = 20;//1,自动类型推导,必须推导出一致的数据类型T, 才可以使用cout << "第一次交换:自动类型推导" << endl;myswap(a, b);//正确cout << "a=" << a << endl;cout << "b=" << b << endl;cout << "第二次交换:显示指定类型" << endl;myswap<int>(a, b);cout << "a=" << a << endl;cout << "b=" << b << endl;}
//2,模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()
{cout << "func调用" << endl;
}void test02()
{//func();错误,模板不能独立使用,必须确定出T的模型才可以func<int>();//利用显示指定类型的方式,给T一个类型,才可以使用该模板
}int main()
{test01();test02();system("pause");return 0;
}

1.2.3 函数模板案例

案例描述:

利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序

排序规则从大到小,排序算法为选择排序

分别利用char数组和int数组进行测试 

#include<iostream>
using namespace std;//利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
//规则 从小到大
//算法  选择
//测试 char,数组,int 数组//打印函数模板
template<typename T>
void printArray(T arr[], int len)
{for (int i = 0; i < len; i++){cout << arr[i] << " ";}cout << endl;
}//交换函数模板
template<class T>
void mySwap(T &a, T &b)
{T temp = a;a = b;b = temp;
}//排序算法
template<class T>
void mySort(T arr[], int len)
{for (int i = 0; i < len; i++){int max = i;//认定最大值的下标for (int j = i + 1; j < len; j++){//认定的最大值 比 遍历的数值要小,说明j下边的元素是才是真正的最大值if (arr[max] < arr[j]){max = j;}}if (max != i){//交换max和i元素的下标mySwap(arr[max], arr[i]);}}
}void test02()
{int intArr[] = { 7,5,1,3,9,2,4,6,8 };int num = sizeof(intArr) / sizeof(intArr[0]);mySort(intArr, num);printArray(intArr, num);
}void test01()
{//测试char数组char charArr[7] = "badcef";int num = sizeof(charArr) / sizeof(char);mySort(charArr, num);printArray(charArr, num);
}int main()
{test01();test02();system("pause");return 0;
}

1.2.4 普通函数与函数模板的区别

普通函数与函数模板区别

普通函数调用时可以发生自动类型转换(隐式类型转换)

函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换

如果利用显示指定类型的方式,可以发生隐式类型转换 

示例:

#include<iostream>
using namespace std;//普通函数与函数模板的区别//普通函数调用时可以发生自动类型转换(隐式类型转换)
//函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
//如果利用显示指定类型的方式,可以发生隐式类型转换 //普通数组
int myAdd01(int a,int b)
{return a + b;
}//函数模板
template<class T>
T myAdd02(T a, T b)
{return a + b;
}void test01()
{int a = 10;int b = 20;char c = 'c';cout << "a + b =" << myAdd01(a, b) << endl;cout <<"a + c =" << myAdd01(a, c) << endl;//a - 97 c - 99//自动类型推导cout << "自动类型推导" << endl;cout << myAdd02(a, b) << endl;//cout << myAdd02(a, c) << endl;//报错,不会发生隐式类型转换//显示指定类型cout << "显示指定类型" << endl;cout << myAdd02<int>(a, c) << endl;//会发生隐式类型转换
}int main()
{test01();system("pause");return 0;
}

总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型

 1.2.5 普通函数与函数模板的调用规则

调用规则如下:

1.如果函数模板和普通函数都可以实现,优先调用普通函数

2.可以通过空模板参数列表来强制调用函数模板

3.函数模板也可以发生重载

4.如果函数模板可以产生更好的匹配,优先调用函数模板

示例1:

#include<iostream>
using namespace std;//1.如果函数模板和普通函数都可以实现,优先调用普通函数
void myprint(int a, int b)
{cout << "调用的普通函数" << endl;
}template<class T>
void myprint(T a, T b)
{cout << "调用的模板函数" << endl;
}void test01()
{int a = 10;int b = 10;myprint(a, b);
}int main()
{test01();system("pause");return 0;
}

示例2: 

#include<iostream>
using namespace std;
//2.可以通过空模板参数列表来强制调用函数模板void myprint(int a, int b)
{cout << "调用的普通函数" << endl;
}template<class T>
void myprint(T a, T b)
{cout << "调用的模板函数" << endl;
}void test01()
{int a = 10;int b = 10;myprint<>(a, b);
}int main()
{test01();system("pause");return 0;
}

示例3:

#include<iostream>
using namespace std;
void myprint(int a, int b)
{cout << "调用的普通函数" << endl;
}template<class T>
void myprint(T a, T b)
{cout << "调用的模板函数" << endl;
}template<class T>
void myprint(T a, T b,T c)
{cout << "调用的模板重载函数" << endl;
}void test01()
{int a = 10;int b = 10;//3,函数也可以发生重载int c = 10;myprint(a, b, c);//4,如果函数模板可以产生更好的匹配,优先调用函数模板char c1 = 'a';char c2 = 'c';myprint(c1,c2);}int main()
{test01();system("pause");return 0;
}

 

总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性 

1.2.6 模板的局限性

局限性:

模板的通用性并不是万能的

例如:

template<class T>
void f(T a, T b)
{
a = b;
}

在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了

再例如:

template<class T>
void f(T a, T b)
{if(a>b){...}
}

在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行
因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板

#include<iostream>
using namespace std;
#include<string>//模板的局限性
//模板并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_age = age;}string m_Name;int m_age;
};template<class T> 
bool myCompare(T &a,T &b)
{if (a == b){return true;}else{return false;}
}//利用具体化Person版本实现代码,具体化优先调用
template<>bool myCompare(Person& p1, Person& p2)
{if (p1.m_Name == p2.m_Name && p1.m_age == p2.m_age){return true;}else{return false;}
}void test01()
{int a = 10;int b = 20;bool ret = myCompare(a, b);if (ret){cout << "a==b" << endl;}else{cout << "a!=b" << endl;}
}
void test02()
{Person p1("Tom", 10);Person p2("Tom", 10);bool ret = myCompare(p1, p2);if (ret){cout << "p1==p2" << endl;}else{cout << "p1!=p2" << endl;}
}int main()
{test01();test02();system("pause");return 0;
}

总结:

利用具体化的模板,可以解决自定义类型的通用化

学习模板不是为了写模板,而是在STL能够运用系统提供的模板 

1.3 类模板

1.3.1 类模板语法

类模板作用:

建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。

//语法:template<typename T>类

解释:

template…声明创建模板

typename -表面其后面的符号是一种数据类型,可以用class代替

T… 通用的数据类型,名称可以替换,通常为大写字母

#include<iostream>
using namespace std;
#include<string>//类模板
template<class NameYtpe,class AgeType>
class Person
{
public:Person(NameYtpe name, AgeType age){this->m_Name = name;this->m_Age = age;}void ShowPerson(){cout << "name: " << this->m_Name <<"\t" << "age: " << this->m_Age << endl;}NameYtpe m_Name;AgeType m_Age;
};void test01()
{Person<string, int>p1("孙悟空", 99);p1.ShowPerson();
}int main()
{test01();system("pause");return 0;
}

 总结:类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板

1.3.2 类模板与函数模板区别

类模板与函数模板区别主要有两点:

1.类模板没有自动类型推导的使用方式

2.类模板在模板参数列表中可以有默认参数

示例:

#include<iostream>
using namespace std;
#include<string>//类模板与函数模板的区别
template<class NameYtpe, class AgeType = int>
class Person
{
public:Person(NameYtpe name, AgeType  age ){this->m_Name = name;this->m_Age = age;}void ShowPerson(){cout << "name: " << this->m_Name << "\t" << "age: " << this->m_Age << endl;}NameYtpe m_Name;AgeType m_Age;
};//1.类模板没有自动类型推导的使用方式
void test01()
{//Person p("孙悟空",1000);Person<string, int>p1("孙悟空", 99);//只能用显示指定类型p1.ShowPerson();
}
//2.类模板在模板参数列表中可以有默认参数
void test02()
{Person<string>p2("猪八戒", 999);p2.ShowPerson();
}int main()
{test01();test02();system("pause");return 0;
}

 

1.3.3 类模板中成员函数创建时机

类模板中成员函数和普通类中成员函数创建时机是有区别的:

普通类中的成员函数一开始就可以创建

类模板中的成员函数在调用时才创建

// 类模板中成员函数创建时机
//普通类中的成员函数一开始就可以创建//类模板中的成员函数在调用时才创建#include<iostream>
using namespace std;class Person1
{
public:void showPerson1(){cout << "Person1 show" << endl;}
};class Person2
{
public:void showPerson2(){cout << "Person2 show" << endl;}
};template<class T>
class Myclass
{
public:T obj;//类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成//类模板中的成员函数void func1(){obj.showPerson1();}void func2(){obj.showPerson2();}
};void test01()
{Myclass<Person1>m;m.func1();//m.func2();//编译会出错,说明函数调用时才会去创建成员函数
}int main()
{test01();system("pause");return 0;
}

1.3.4 类模板对象做函数参数

学习目标:

类模板实例化出的对象,向函数传参的方式

共有三种传入方式:

1.指定传入的类型   直接显示对象的数据类型

2.参数模板化   将对象中的参数变为模板进行传递

3. 将这个对象类型   模板化进行传递3.整个类模板化

示例:

#include<iostream>
using namespace std;
#include<string>
//类模板对象做函数参数template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}void showPerson(){cout << "name: " << this->m_Name << "\t" << "age: " << this->m_Age << endl;}T1 m_Name;T2 m_Age;
};void printPerson1(Person<string,int>&p)
{p.showPerson();
}//1,指定传入类型
void test01()
{Person<string ,int>p("孙悟空", 100);printPerson1(p);
}//2,参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{p.showPerson();cout << "T1的类型为:" << typeid(T1).name() << endl;cout << "T1的类型为:" << typeid(T2).name() << endl;
}void test02()
{Person<string, int>p("猪八戒", 90);printPerson2(p);
}//3,整个类模板化
template<class T>
void printPerson3(T &p)
{p.showPerson();cout << "T1的类型为:" << typeid(T).name() << endl;
}void test03()
{Person<string, int>p("唐增", 90);printPerson3(p);
}int main()
{test01();test02();test03();system("pause");return 0;
}

总结:

通过类模板创建的对象,可以有三种方式想函数中进行传参

使用比较广泛的是第一种:指定传入的类型 

1.3.5 类模板与继承

当类模板碰到继承时,需要注意一下几点:

当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T类型

如果不指定,编译器无法给子类分配内存

如果想灵活指定出父类中T的类型,子类也需变为类模板

#include<iostream>
using namespace std;
#include<string>//类模板与继承
template<class T>
class Base
{T m;
};//class Son:public Base//错误,必须要指定父类中的T类型,才能继承给子类
class Son1 :public Base<int>
{};void test01()
{Son1 s1;
}//如果想灵活指定出父类中T的类型,子类也需变为类模板
template<class T1,class T2>
class Son2 :public Base<T2>
{
public:Son2(){cout << "T1的类型为:" << typeid(T1).name() << endl;cout << "T2的类型为:" << typeid(T2).name() << endl;}T1 obj;
};void test02()
{Son2<int, char>S2;
}int main()
{//test01();test02();//test03();system("pause");return 0;
}

总结:如果父类是类模板,子类需要指定出父类中T的数据类型 

1.3.6 类模板成员函数类外实现

示例:

#include<iostream>
using namespace std;
#include<string>template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void ShowPerson();T1 m_Name;T2 m_Age;
};//构造函数的类外实现
template<class T1, class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{this->m_Name = name;this->m_Age = age;
}//成员函数类外实现
template<class T1, class T2>
void Person<T1, T2>::ShowPerson()
{cout << "name: " << this->m_Name << "\t" << "age: " << this->m_Age << endl;
}void test01()
{Person<string, int>P("Tom", 20);P.ShowPerson();
}int main()
{test01();system("pause");return 0;
}

总结:类模板中成员函数类外实现时,需要加上模板参数列表 

1.3.7 类模板分文件编写

学习目标:

掌握类模板成员函数分文件编写产生的问题以及解决方式

问题:

类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:

解决方式1:直接包含.cpp源文件

解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制

我们首先将类模板成员函数类外实现的文件分为以下三个文件:

Person.h

#include"Person.h"
//构造函数的类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{this->m_Name = name;this->m_Age = age;
}//成员函数类外实现
template<class T1, class T2>
void Person<T1, T2>::ShowPerson()
{cout << "name: " << this->m_Name << "\t" << "age: " << this->m_Age << endl;
}

Person.cpp

#pragma once
#include<iostream>
using namespace std;
#include<string>//类模板分文件编写问题以及解决
template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void ShowPerson();T1 m_Name;T2 m_Age;
};

 类模板分文件编写.cpp

#include"person.h"
void test01()
{Person<string, int>P("Tom", 20);P.ShowPerson();
}int main()
{test01();system("pause");return 0;
}

 解决方法1:将类模板的头文件改为:#include"person.cpp"即可运行

解决方法2:将.h和.cpp中的内容写到一起,将后缀名改为.hpp文件

 

总结:主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp 

1.3.8 类模板与友元

学习目标:

掌握类模板配合友元函数的类内和类外实现

全局函数类内实现-直接在类内声明友元即可

全局函数类外实现-需要提前让编译器知道全局函数的存在

示例:

#include<iostream>
using namespace std;
#include<string>template<class T1, class T2>
class Person;//类外实现
template<class T1, class T2>
void PrintPerson2(Person<T1, T2>p)
{cout << "类外实现---姓名:" << p.m_Name << "年龄:" << p.m_Age << endl;
}//通过全局函数,打印Perosn信息
template<class T1,class T2>
class Person
{//全局函数类外实现//加空模板参数列表//如果全局函数 是类外实现,需要让编译器提前指定这个函数的存在friend void PrintPerson2<>(Person<T1, T2>p);
public://全局函数 类内实现friend void PrintPerson(Person<T1, T2>&p){cout << "name: " << p.m_Name << "\t" << "age: " << p.m_Age << endl;}Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}
private:T1 m_Name;T2 m_Age;
};void test01()
{Person<string, int>p("Tom", 100);PrintPerson(p);
}
//全局函数类外实现
void test02()
{Person<string, int>p("Jerry", 20);PrintPerson2(p);
}int main()
{test01();test02();system("pause");return 0;
}

总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别 

1.3.9 类模板案例

 案例描述:实现一个通用的数组类,要求如下:

可以对内置数据类型以及自定义数据类型的数据进行存储

将数组中的数据存储到堆区

构造函数中可以传入数组的容量

提供对应的拷贝构造函数以及operator=防止浅拷贝问题

提供尾插法和尾刚法对数组中的教据进行增加和刷除

可以通过下标的方式访问数组中的元素

可以获取数组中当前元素个数和数组的容量

思路:

 

相关文章:

C++之模板

本阶段主要针对C泛型编程和ST技术做详细讲解&#xff0c;探讨C更深层的使用 1.1 模板的概念 模板就是建立通用的模具&#xff0c;大大提高复用性 模板的特点: 模板不可以直接使用&#xff0c;它只是一个框架 模板的通用并不是万能的 1.2 函数模板 C另一种编程思想称为 …...

Ubuntu Flask 运行 gunicorn+Nginx 部署

linux Ubuntu 下运行python 程序出现killed 原因&#xff1a;CPU或内存限制&#xff1a;在华为云上&#xff0c;你可能有CPU或内存使用的限制。例如&#xff0c;如果你使用的是一个固定大小的实例&#xff0c;那么超过该实例的CPU或内存限制可能会导致进程被杀死。 参考&am…...

Tuxera NTFS 2023安装使用教程 Tuxera NTFS破解版 Tuxera NTFS for Mac优惠

对于必须在Windows电脑和Mac电脑之间来回切换的Mac朋友来说&#xff0c;跨平台不兼容一直是一个巨大的障碍&#xff0c;尤其是当我们需要使用NTFS格式的硬盘在Windows和macOS之间共享文件时。因为Mac默认不支持写入NTFS磁盘。 为了解决这一问题&#xff0c;很多朋友会选择很便捷…...

Linux-centos如何搭建yum源仓库

1.本地搭建&#xff08;无需连接外网&#xff09; 1.1检查网络配置&#xff0c;及网络连接 打开虚拟机&#xff0c;点击【编辑——虚拟网络编辑器】 点击【仅主机模式】查看子网段是否和局内IP匹配 进入局内&#xff0c;查看网络IP是否在你上述设置的网段内&#xff0c;如果不…...

Vue组件中引入jQuery

两种在vue中引入jQuery的方式 1、普通html中使用jQuery 将jQuer的文件导入到项目中&#xff0c;然后直接使用<script src"jQuery.js"></script>即可。 <script src"jQuery.js"></script> 2、vue组件中使用jQuery 安装依赖 c…...

设计模式 --3:装扮模式

结构图 代码 #include<iostream>using namespace std;class person { public:person() {};person(string name) { this->name name; }virtual void show() {cout << "装扮的:" << this->name << endl;} private:string name; }; //装…...

element-plus中的表单校验

1. 简单校验&#xff1a; 1.1 在script中给出校验规则对象&#xff0c;主要属性名与form对象的属性名一致1.2 一个字段的校验规则可以有多个&#xff0c;值是一个数组&#xff0c;数组中的一个对象就是一条校验规则1.3 主要校验规则&#xff1a; 1.3.1 required&#xff1a;是…...

ros小问题之roslaunch tab补不全新增的功能包

在学习Gazebo这一章节时&#xff0c;通过catkin_create_pkg命令创建了仿真机械臂所需的软件包&#xff0c;创建完成后里面的内容直接拷贝了教材配套的文件&#xff0c;但在roslaunch时&#xff0c;摁tab键补不全新加的包。 重新source catkin_ws/devel/setup.bash不起作用&…...

C#常见的.Net类型(二)

目录 一、在集合中存储多个对象理解集合的选择1.列表2.字典3.堆栈4.队列5.集 二、使用Span、索引和范围Span索引范围 处理类型和属性1.特性2.创建自定义特性3.反射 一、在集合中存储多个对象 处理集合的常见类型 类型描述List动态大小的数组&#xff0c;可以按索引访问Dictio…...

oracle临时表空间不释放

项目报错 nested exception is java.sql.SQLException: ORA-01652: unable to extend temp segment by 128 in tablespace TEMP 原因是临时表空间满了&#xff0c;临时表空间一直增长&#xff0c;未释放导致临时表空间使用率100%。 查询临时表空间使用率 --临时表空间利用率…...

Chapter 13 Techniques of Design-Oriented Analysis: The Feedback Theorem

Chapter 13 Techniques of Design-Oriented Analysis: The Feedback Theorem 从这一章开始讲负反馈Control系统和小信号建模. 13.2 The Feedback Theorem 首先介绍 Middlebrook’s Feedback Theorem 考虑下面负反馈系统 传输函数 Guo/ui G ( s ) u o u i G ∞ T 1 T G…...

科研学习|论文解读——美国政治经济中的权力:网络分析(JASIST, 2019)

论文原题目 Power in the U.S. political economy: A network analysis 摘要 美国政治经济的许多特征产生于大型政治和经济机构之间的互动&#xff0c;然而我们对它们的互动性质和这些机构之间的权力分配知之甚少。在本文中&#xff0c;对总部设在美国的组织的网络进行了详细的…...

常用的git命令

一、常用的git命令 1. 配置 git config --local user.name "xxx" ---仅对当前Git仓库有效。配置信息将保存在当前Git仓库的 .git/config 文件中 local优先级最高&#xff0c;会覆盖其他范围的相同配置 git config --global user.email "xxx" ---全局…...

【AI】用iOS的ML(机器学习)创建自己的AI App

用iOS的ML(机器学习)创建自己的AI App 目录 用iOS的ML(机器学习)创建自己的AI App机器学习如同迭代过程CoreML 的使用方法?软件要求硬件开始吧!!构建管道:设计和训练网络Keras 转 CoreML将模型集成到 Xcode 中结论推荐超级课程: Docker快速入门到精通Kubernetes入门到…...

远程调用初体验笔记

远程调用初体验笔记 微服务架构通常将系统拆分成多个独立的服务单元&#xff0c;每个服务单元都专注于实现特定的业务功能。当一个服务需要使用另一个服务提供的功能时&#xff0c;就可以通过远程调用来实现。 使用步骤 1.步骤 Spring给我们提供了一个RestTemplate工具&#…...

反无人机电子护栏:原理、算法及简单实现

随着无人机技术的快速发展&#xff0c;其在航拍、农业、物流等领域的应用日益广泛。然而&#xff0c;无人机的不规范使用也带来了安全隐患&#xff0c;如侵犯隐私、干扰航空秩序等。为了有效管理无人机&#xff0c;反无人机电子护栏技术应运而生。 目录 一、反无人机电子护栏…...

Java项目利用Redisson实现真正生产可用高并发秒杀功能 支持分布式高并发秒杀

Java中的高并发秒杀场景下我们可以使用redisson来实现高并发秒杀功能, 以下就是一个可用于生产环境的高并发秒杀示例代码: pom依赖 <!-- https://mavenlibs.com/maven/dependency/org.redisson/redisson --><dependency><groupId>org.redisson</groupId&…...

0104行列式的性质-行列式-线性代数

记 D ∣ a 11 a 12 ⋯ a 1 n a 21 a 22 ⋯ a 2 n ⋯ ⋯ ⋯ a n 1 a n 2 ⋯ a n n ∣ D\begin{vmatrix}a_{11}&a_{12}&\cdots &a_{1n}\\a_{21}&a_{22}&\cdots&a_{2n}\\\cdots&\cdots&&\cdots\\a_{n1}&a_{n2}&\cdots&a_{nn}\en…...

k8s HPA 自动伸缩机制 (配置,资源限制,)

目录 一、概念 核心概念 工作原理 HPA 的配置关键参数 关键组件 使用场景 注意事项 如何确保程序稳定和服务连续 二、metrics-server 部署 metrics-server 准备 metrics-server 镜像: 使用 Helm 安装 metrics-server: 配置 metrics-server: 安装 metrics-server: …...

vulhub中GIT-SHELL 沙盒绕过漏洞复现(CVE-2017-8386)

GIT-SHELL 沙盒绕过&#xff08;CVE-2017-8386&#xff09;导致任意文件读取、可能的任意命令执行漏洞。 测试环境 为了不和docker母机的ssh端口冲突&#xff0c;将容器的ssh端口设置成3322。本目录下我生成了一个id_rsa&#xff0c;这是ssh的私钥&#xff0c;连接的时候请指…...

SpringBoot+vue3打造企业级一体化SaaS系统

SpringBootvue3打造企业级一体化SaaS系统 简介&#xff1a;    全面提升前后端技术水平&#xff0c;独立完成全栈项目开发能力&#xff0c;快速进击全栈工程师&#xff0c;最终在面试中脱颖而出。整合后端主流技术&#xff08;Spring Boot、物理数据库隔离、加载动态权限、多…...

探讨TCP的可靠性以及三次握手的奥秘

&#x1f31f; 欢迎来到 我的博客&#xff01; &#x1f308; &#x1f4a1; 探索未知, 分享知识 !&#x1f4ab; 本文目录 1. TCP的可靠性机制1.2可靠性的基础上,尽可能得提高效率 2. TCP三次握手过程3. 为何不是四次握手&#xff1f; 在互联网的复杂世界中&#xff0c;TCP&am…...

openai常见的两个错误:BadRequestError和OpenAIError

错误1:openai.OpenAIError: The api_key client option must be set either by passing api_key..... 在通过openai创建客户端必须要设置api key&#xff0c;如果你事先已经在本机的环境中设置未起效可以手动设置&#xff0c;注意手动设置时不要用下面的形式 import openai f…...

2核4g服务器够用吗?

2核4G服务器够用吗&#xff1f;够用。阿腾云以2核4G5M服务器搭建网站为例&#xff0c;5M带宽下载速度峰值可达640KB/秒&#xff0c;阿腾云以搭建网站为例&#xff0c;假设优化后平均大小为60KB&#xff0c;则5M带宽可支撑10个用户同时在1秒内打开网站&#xff0c;并发数为10&am…...

数据仓库数据分层详解

数据仓库中的数据分层是一种重要的数据组织方式&#xff0c;其目的是为了在管理数据时能够对数据有一个更加清晰的掌控。以下是数据仓库中的数据分层详解&#xff1a; 原始数据层&#xff08;Raw Data Layer&#xff09;&#xff1a;这是数仓中最底层的层级&#xff0c;用于存…...

unity内存优化之AB包篇(微信小游戏)

1.搭建资源服务器使用(HFS软件(https://www.pianshen.com/article/54621708008/)) using System.Collections; using System.Collections.Generic; using UnityEngine;using System;public class Singleton<T> where T : class, new() {private static readonly Lazy<…...

白话模电:3.三极管(考研面试与笔试常考问题)

一、三极管的简单判断 1.判断三极 1)给了图 左边是b,有箭头是e,剩下是c 2)给了电位 b:中间值&#xff0c;e:较近值(离中间值)&#xff0c;c:较远值(离中间值) 2.判断流向 bc同向(共同流向“|”或共同流离“|”)&#xff0c;e与bc反向 3.判断材料 4.判断类型 5.判断能否构…...

LeetCode 395. 至少有K个重复字符的最长子串

解题思路 一道滑动窗口题型&#xff0c;不过滑动窗口的长度是不同种类元素的个数。 这里需要定义两个变量 cnt,overk。overk表示的是满足大于k的字符数, cnt表示的是该窗口中不同元素的个数且cnt>1&&cnt<26。 相关代码 class Solution {public int longestSub…...

C#重新认识笔记_ FixUpdate + Update

C#重新认识笔记_ FixUpdate Update Update: 刷新频率不一致,非物理对象的移动&#xff0c;简单的刷新可用&#xff0c; FixedUpdate: 刷新频率一致,按照固定频率刷新&#xff0c;一般调用FixedUpdate之后&#xff0c;会立即进入必要的物理计算中,因此&#xff0c;任何影响刚…...

Django 解决新建表删除后无法重新创建等问题

Django 解决新建表删除后无法重新创建等问题 问题发生描述处理办法首先删除了app对应目录migrations下除 __init__.py以外的所有文件:然后&#xff0c;删除migrations中关于你的app的同步数据数据库记录最后&#xff0c;重新执行迁移插入 问题发生描述 Django创建的表&#xf…...