C++11:常用语法汇总

目录

  • 🍁统一的列表初始化 { }
    • initializer_list
  • 🍁decltype 推导表达式类型
  • 🍁可变参数模板
    • 解析可变参数包
      • 方法一
      • 方法二
  • 🍁lambda 表达式
    • 捕捉列表的使用
    • 运用场景举例
    • lambda表达式 与 函数对象

🍁统一的列表初始化 { }

在 C++98 标准中,花括号 { } 可以对数组、结构体元素进行同一的初始化处理:

struct Point
{int _x;int _y;
};int main()
{int arr[] = { 1, 2, 3, 4, 5 }; //初始化数组char str[] = { "hello world" };Point p = { 1, 2 };return 0;
}

时间来到 C++11 的时候,就扩大了花括号 { } 列表的使用范围。

花括号 { } 可以用来所有的内置类型自定义类型;简单的来说就是可以用花括号来初始化一切变量,并且可以省略赋值符号。

struct Point
{int _x;int _y;
};int main()
{int x1 = 10;int x2 = { 20 }; //初始化变量x2int array1[] { 1, 2, 3, 4, 5 }; //初始话array1数组省略赋值符号char str[] { "hello world" };Point p { 1, 2 };return 0;
}

列表初始化可以对 new 对象进行初始化:

int* pa = new int[5]{ 1, 2, 3, 4, 5 };

创建对象时使用列表初始化会调用该对象的构造函数:

class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day){std::cout << "Date(int year, int month, int day)" << std::endl;}private:int _year;int _month;int _day;
};int main()
{Date d(2024, 1, 1); //调用构造函数//使用列表初始化Date d1 = { 2024, 1, 2 }; //构造+拷贝构造==>编译优化为构造Date d2{ 2024 ,1, 3 };return 0;
}

在这里插入图片描述

列表初始化还可以运用在容器上:

#include <vector>
#include <list>int main()
{std::vector<int> v1 = { 1, 2, 3, 4, 5 }; //初始化vector容器std::list<int> lt1 = { 10, 20, 30, 40 }; //初始化list容器return 0;
}

注意:在初始化 vector 和 list 这样的容器的时候,并不是直接去调用 vector 和 list 的构造函数。vector 和 list 的构造函数也不支持这么多参数的传参。

initializer_list

花括号里面的初始化内容,C++会识别成 initializer_list

int main()
{auto i1 = { 1, 2, 3, 4, 5, 6 };auto i2 = { 10, 20, 30, 40, 50, 60 };std::cout << typeid(i1).name() << std::endl;std::cout << typeid(i2).name() << std::endl;return 0;
}

在这里插入图片描述

initializer_list 是一个类:
在这里插入图片描述
initializer_list 会构建一个类型,这个类型有两个指针:第一个指针指向列表的开始,另一个指针指向列表结尾的下一个位置

在这里插入图片描述

int main()
{auto i1 = { 1, 2, 3, 4, 5, 6 };auto it1 = i1.begin();auto it2 = i1.end();std::cout << it1 << std::endl;std::cout << it2 << std::endl;std::cout << it2 - it1 << std::endl; return 0;
}

在这里插入图片描述
尾指针地址减去列表首元素的地址,得到就是列表元素个数

提示:列表中的内容是不能修改的,因为它们是被存放到常量区

int main()
{auto i1 = { 1, 2, 3, 4, 5, 6 };auto it = i1.begin();(*it)++; //报错return 0;
}

在这里插入图片描述
当然,我们也可以使用这个类:

int main()
{std::initializer_list<int> il = { 1, 2, 3, 4, 5, 6 };for (auto& e : il){std::cout << e << " ";}std::cout << std::endl;return 0;
}

在这里插入图片描述

为什么 vector 和 list 容器能够支持列表初始化呢?

C++11 标准出来后,像 vector 和 list 这样的容器推出了这样的构造函数:

vector(initializer_list<value_type> il, const allocator_type& alloc = allocator_type());

vector 和 list 通过 initializer_list类去初始化列表,进而实现 vector 和 list 的构造初始化。

下面来实现一个简单版的 vector 支持 initializer_list 的构造函数:

vector(std::initializer_list<T> il)
{reserve(il.size()); //检查容量for (auto& e : il)push_back(e);
}

下面再来举例几个列表初始化的案例:

#include <map>
#include <set>
#include <vector>int main()
{std::vector<int> v1 = { 1, 2, 3, 4, 5 };std::vector<int> v2 = { 10, 20, 30, 40, 50 };std::vector<std::vector<int>> vv1 = { v1 ,v2 };//对象初始化std::vector<std::vector<int>> vv2 = { std::vector<int>{100, 200, 300}, v2 }; //匿名对象初始化std::vector<std::vector<int>> vv3 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; //编译器自动推导类型std::set<std::vector<int>> s = { {1, 2, 3}, {10, 20, 30} };std::map<std::string, int> m = { {"苹果", 1}, {"香蕉", 2}, {"哈密瓜", 3} };return 0;
}

🍁decltype 推导表达式类型

decltype 是 C++11 中引入的一个新的关键字,主要用于 声明和推导表达式的类型

int main()
{int x = 10;int y = 20;double a = 1.1;double b = 2.2;decltype (x + y) ret1;decltype (b - a) ret2;decltype (&x) ret3;std::cout << typeid(ret1).name() << std::endl;std::cout << typeid(ret2).name() << std::endl;std::cout << typeid(ret3).name() << std::endl;return 0;
}

在这里插入图片描述

decltype 可以用于 auto 推导不了类型的场景,例如模板的实例化传参:

int main()
{double a = 1.1;double b = 2.2;//要求vector存储与 a*b 表达式的返回值一致的类型std::vector<decltype(a * b)> v; //利用 decltype 推导表达式的类型return 0;
}

🍁可变参数模板

C++98/03中,类模板的和函数模板中只能含有固定数量的模板参数,比较局限。在 C++11 引入了可变参数模板,可以创建可变参数函数和类模板。

示例:

template <class ...Args>  //...Args表示模板参数包
void ShowList(Args... args)
{}int main()
{ShowList();ShowList(1);ShowList(1, 'x'); //不会限制传入的类型和参数的个数return 0;
}
  • Args是一个模板参数包,args是一个函数形参参数包

在函数声明一个形参参数包 Args... args ,表示这个参数包中可以被传入的参数个数是 0 个甚至是多个参数

也可以用sizeof来统计传入参数的个数,如下:

#include <iostream>
using namespace std;template<typename ...Args>
void ShowList(Args... args)
{cout << sizeof...(args) << endl; //统计传入参数的个数
}int main()
{ShowList();ShowList(1);ShowList(1, 'x'); //不会限制类型ShowList(1, 'x', "abc"); return 0;
}

在这里插入图片描述

解析可变参数包

可变参数的作用我们看到了,就是解决了传参个数的限制。但是,当一个函数设置了参数包,那么在函数内部我们如何去获取可变参数包参数变量呢?

方法一

C++11提供了一个递归的方式来解析可变参数包,在函数模板中多设置一个模板参数:

void ShowList()
{cout << endl;
}template<typename T, typename ...Args>
void ShowList(const T& val, Args... args)
{cout << val << " "; ShowList(args...);//传入参数包,递归解析
}
int main()
{ShowList();ShowList(1);ShowList(1, 'x'); ShowList(1, 'x', "abc"); return 0;
}

在这里插入图片描述

当参数被传入后,T 模板参数 val 会获取首次传入的参数。在之后都是获取到可变参数包的参数内容,每获取一次,可变参数个数递归传给下一次 ShowList 的参数个数就会减少一次。至此,就达到解析可变参数包的效果

由于在参数包中传入的参数个数可以是 0 个,因此当参数包个数为 0 时也就是递归结束的条件!

方法二

通过调用函数的方式初始化数组来解析参数包:

template<typename T>
int PrintArg(const T& t)
{cout << t << " ";return 0;
}
template<typename ...Args>
void ShowList(Args... args)
{int arr[] = { PrintArg(args)... }; //初始化数组cout << endl;
}
int main()
{ShowList();ShowList(1);ShowList(1, 'x'); ShowList(1, 'x', "abc"); return 0;
}

在这里插入图片描述

ShowList(1, 'x', "abc"); 为例子,编译器在编译阶段会将上面代码解析为下面这样:

void ShowList(int a1, char a2, string a3)
{int arr[] = { PrintArg(a1), PrintArg(a2), PrintArg(a3) };cout << endl;
}

使用参数包会影响编译器的效率,因为要推演函数参数的类型。对此,一般的参数包都会设计成下面这样的情况:

这里拿 ShowList 模板函数为例子

template<typename ...Args>
void ShowList(Args&&... args) //这里的&&表示折叠引用
{int arr[] = { PrintArg(args)... }; //初始化数组cout << endl;
}

在参数包后加上 &&,在推演参数类型时,传递的参数为左值 && 就会折叠为左值;传递的参数为右值 && 就没有变化还是右值;因此,在参数包后加上 &&,也被称为万能引用

🍁lambda 表达式

介绍 lambda 表达式前,先来看这样的一个例子:

struct Goods
{string _name;  // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };return 0;
}

vector 容器中的 Goods 对象有这样的属性:价格、名称 和 重量。

现在,如果想要将 vector 容器中的 Goods对象 按照价格进行降序排序,正常操会是这样的:先定义一个对货物的价格做比较的仿函数,再使用 sort 函数进行排序处理

struct ComparePriceGreater //定义仿函数
{bool operator()(const Goods& g1, const Goods& g2){return g1._price > g2._price;}
};int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };//降序sort(v.begin(), v.end(), ComparePriceGreater());return 0;
}

为了方便展示,这里直接使用了 VS 的监视窗口。

排序前:
在这里插入图片描述

排序后结果如下:
在这里插入图片描述

可以看到在 vector 容器中,各个物品都是按照价格降序的顺序进行排列。

在使用仿函数时,需要定义一个类,实现对应的函数运算符重载。仿函数的名字,定义都是有些许的繁琐和麻烦。

在 C++11引出了这么一个新的语法:lambda 表达式 可以代替仿函数而去使用 sort 函数。

下面就来介绍一下 lambda 表达式。

lambda 表达式由以下几个部分构成:

  • [] 捕捉列表:编译器会根据 [] 来判断代码是否为 lambda 表达式。[] 捕捉列表 用于捕获上下域中的变量提供给lambda 函数使用
  • ()参数列表:与普通的函数参数列表一样,当形参不存在时,()可以省略不写
  • mutable:通常情况下,lambda 表达式总是一个const 函数,mutable 关键字用于取消 lambda表达式的常性,可以省略
  • ->返回值类型:用追踪返回类型形式声明函数的返回值类型,返回值类型明确情况下可以省略不写,由编译器自动推导
  • {}函数体:实现 lambda 表达式的功能,函数体内部可以使用形参列表的内容,以及被捕获的变量值

lambda 表达式的书写格式:[] () mutable->return-type {}

注意:lambda 表达式返回值是一个对象

下面来举个示例,实现两个数相加的 lambda 表达式 :

int main()
{std::cout << [](int x, int y)->int { return x + y; }(1, 2) << std::endl;return 0;
}

在这里插入图片描述
但是这样写 lambda表达式很抽象,不利于代码的阅读。

lambda 表达式返回值是一个对象,可以将上面代码改写为下面这样:

int main()
{auto add = [](int x, int y)->int { return x + y; }; //让编译器自动推导lambda表达式的类型std::cout << add(10, 20) << std::endl;return 0;
}

在这里插入图片描述

将 lambda 表达式返回,编译器会自动推导 lambda表达式类型定义为add。实例化一个 add 匿名对象执行对应的相加功能,通过打印输最后出到终端。

上面是通过传参的方式实现两个数相加的功能,下面用 lambda 表达式的捕获方式来实现相加功能:

int main()
{int x = 10, y = 20;auto add = [x, y]()->int { return x + y; }; //用[]来捕获x和y的值std::cout << add() << std::endl;return 0;
}

在这里插入图片描述

对 lambda 表达式有了一定了解后,我们再回过头来看看先前举的例子:

struct ComparePriceGreater //定义仿函数
{bool operator()(const Goods& g1, const Goods& g2){return g1._price > g2._price;}
};int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };//降序sort(v.begin(), v.end(), ComparePriceGreater());return 0;
}

写仿函数的进行排序的方式是不是太过于有点麻烦了,我们可以将仿函数改写成 lambda 表达式:

int main()
{vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) //使用lambda表达式{return g1._price > g2._price;});return 0;
}

排序前:
在这里插入图片描述

排序后:
在这里插入图片描述
使用lambda表达式进行排序的实现效果跟使用仿函数一样

捕捉列表的使用

下面用 lambda 表达式实现 swap 函数:

可以通过参数列表来实现,不过在使用参数列表时,需要用引用参数来接收:

int main()
{int x = 10, y = 20;//引用传入变量,正常值拷贝不会影响lambda表达式外的变量auto swap = [](int& x, int& y) {int tmp = x;x = y;y = tmp;};swap(x, y); //实例化swap匿名对象cout << x << " " << y << endl;	return 0;
}

在这里插入图片描述

lambda 表达式内部作用域 与 当前使用 lambda表达式 的函数作用域是分开的

也就是说:在当前函数中的变量,在 lambda 表达式内部是使用不了的。如果,想要在 lambda 表达式中使用当前函数的变量,有两种方式:参数列表传参捕捉列表

如上举例,可以想象成函数传参。

下面再来通过捕获列表来实现 swap交换功能:

int main()
{int x = 10, y = 20;auto swap = [x, y]() //捕获x,y变量{int tmp = x;x = y;y = tmp;};swap();cout << x << " " << y << endl;return 0;
}

但是,直接捕获的变量,对其直接进行修改会报错:
在这里插入图片描述
在 lambda表达式中 被捕获的变量是按照拷贝的形式

这里的 x 和 y 变量被捕获到 lambda表达式后,是被 const 修饰过的,直接进行值修改会报错

捕捉列表有两种捕获变量的方式:传值捕捉传引用捕捉

传值捕捉传引用捕捉 可以在捕捉列表中任意组合,下面来举例几个案例:

int x = 10, y = 20;
[&]() {};//全部传引用捕捉
[=]() {};//全部传值捕捉//混合捕捉
[&x, y]() {};
[&, x]() {};
[=, &y]() {};

捕捉列表不能重复捕捉同一个变量,下面这种情况编译器会报错:

int x = 10;
[=, x]() {}; //出错

回到刚刚实现的 lambda 表达式。如果想要通过 传值捕捉 实现 swap 交换的功能,就要在 lambda 表达式中就要加上 mutable关键字:

int main()
{int x = 10, y = 20;auto swap = [x, y]() mutable //捕获x,y变量,使用mutable关键字{int tmp = x;x = y;y = tmp;};swap();cout << x << " " << y << endl;return 0;
}

在这里插入图片描述
当然,也可以通过 传引用捕捉 的方式实现对应的功能:

int main()
{int x = 10, y = 20;auto swap = [&x, &y]() //传引用捕捉{int tmp = x;x = y;y = tmp;};swap();cout << x << " " << y << endl;return 0;
}

在这里插入图片描述

运用场景举例

实现这样的一个程序,在这个程序中创建线程池,使得每个线程都能够执行打印特定数字的功能:

#include <thread>
#include <vector>using namespace std;int main()
{int n = 0;//创建n个线程cin >> n;vector<thread> thds(n); //创建n个默认构造线程for (int i = 0; i < n; i++){size_t m = 0;cin >> m; //输入打印数的范围//创建线程池,使每个线程执行打印功能thds[i] = thread([i, m]() //移动赋值,创建的匿名线程是将亡值{for (int j = 0; j < m; j++){//打印对应线程编号与数字cout << this_thread::get_id() << ":" << j << endl;}cout << endl;});}//等待线程池for (auto& th : thds) th.join(); //这里必须传引用,线程没有拷贝构造(没有意义)return 0;
}

lambda表达式 与 函数对象

先来介绍一下函数对象:函数对象,又被称为仿函数。实现一个类,在这个类中实现一个 operator() 运算符重载。实例化出这个类对象,在调用 operator() 时,就像调用函数那般。就被称为仿函数。

下面实现一个仿函数 和 lambda 表达式,实现的功能都类似:

class Rate
{
public:Rate(double rate) : _rate(rate){}double operator()(double money, int year){return _rate * money * year;}
private:double _rate;
};int main()
{//函数对象double rate = 0.49;Rate r1(rate);//构造r1(1000, 2);//lambda表达式auto r2 = [=](double money, int year)->double{return money * year * rate;};r2(1000, 2);return 0;
}

在VS2022调试下,查看反汇编:
在这里插入图片描述
在这里插入图片描述

下面再来计算一下仿函数的大小和 lambda表达式的大小,还是拿上面的例子:

class Rate
{
public:Rate(double rate) : _rate(rate){}double operator()(double money, int year){return _rate * money * year;}
private:double _rate;
};int main()
{double rate = 0.49;auto r2 = [=](double money, int year)->double{return money * year * rate;};cout << sizeof Rate << endl; //查看Rate类的大小cout << sizeof r2 << endl; //查看r2的lambda表达式的大小return 0;
}

在这里插入图片描述

反观底层,仿函数和lambda表达式都是类似的汇编调用方式。而且,如果 lambda表达式捕获的变量 与 仿函数类中的成员一样,那么计算的大小都是一样的。

可以这样说:在编译器眼里,lambda表达式就是仿函数。只不过在用户表面看来,两个表达式方式是那么的不一样。

lambda 表达式就介绍到这里。

C++11新增的语法当然还不止这些,如果对 C++11 还感兴趣的老铁,可以看看小编的另一篇文章:C++入门语法介绍

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

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

相关文章

STM32F407-驱动SHT41采集温湿度

STM32F407-驱动SHT41采集温湿度 SHT41 SHT41通过I2C方式进行驱动 从机地址&#xff1a; 0x44 获取数据方式 1&#xff09;先发送I2C写&#xff0c;写入特定指令 2&#xff09;延时一段时间&#xff0c;等待SHT41处理 3&#xff09;再进行I2C读&#xff0c;读数据即可 一些…

Ansible(二)

一、Playbook基础 1.1 Playbook定义 Playbook其实是Ansible服务的一个配置文件&#xff0c;Ansible使用Playbook的YAML语言配置编写成操作需求&#xff0c;实现对远端主机或策略部署&#xff0c;实现对远端主机的控制与管理。 1.2 Playbook组成 Tasks&#xff1a;任务&…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 垂直布局Vertical Layout

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 布局管理器 | 垂直布局Vertical Layout 文章编号&#x…

渗透测试-信息收集

网络安全信息收集是网络安全领域中至关重要的一环&#xff0c;它涉及到对目标系统、网络或应用进行全面而细致的信息搜集和分析。这一过程不仅有助于理解目标网络的结构、配置和潜在的安全风险&#xff0c;还能为后续的渗透测试、风险评估和安全加固提供有力的支持。 在网络安…

安卓开发--新建工程,新建虚拟手机,按键事件响应(含:Android中使用switch-case遇到case R.id.xxx报错)

安卓开发--新建工程&#xff0c;新建虚拟手机&#xff0c;按键事件响应 1.前言2.运行一个工程2.1布局一个Button2.2 button一般点击事件2.2 button属性点击事件2.2 button推荐点击事件&#xff08;含&#xff1a;Android中使用switch-case遇到case R.id.xxx报错&#xff09; 本…

MATLAB 多项式

MATLAB 多项式 MATLAB将多项式表示为行向量&#xff0c;其中包含按幂次降序排列的系数。例如&#xff0c;方程P(x) X 4 7 3 - 5 9可以表示为 p [1 7 0 -5 9]; 求值多项式 polyval函数用于求一个特定值的多项式。例如&#xff0c;在 x 4 时&#xff0c;计算我们之前的多项式…

命令重装Linux系统,无需登录控制面板

命令重装Linux系统&#xff0c;无需登录控制面板 部分无法登录控制面板使用这个脚本 自动安装安装脚本 wget https://lyvba.com/auto.sh bash auto.sh -d 12 -v 64 -a -p $passwd \--mirror https://mirrors.ustc.edu.cn/debian/安装命令参考 # 自动安装 Debian 10 buster …

基于YOLOV8复杂场景下船舶目标检测系统

1. 背景 海洋作为地球上70%的表面积&#xff0c;承载着人类生活、经济发展和生态系统的重要功能。船舶作为海洋活动的主要载体之一&#xff0c;在海上运输、资源开发、环境监测等方面发挥着重要作用。复杂海洋环境下的船舶目标检测成为了海事管理、海洋资源开发和环境保护等领…

人工智能轨道交通行业周刊-第79期(2024.4.22-5.12)

本期关键词&#xff1a;无人机巡检、车机联控、减速顶、Agent、GraphRAG、RAGFlow 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道世界铁路那…

《动手学深度学习》V2(11-18)

文章目录 十一、二 模型选择与过拟合和欠拟合1、模型的选择2、过拟合和欠拟合3、估计模型容量4、线性分类器的VC维5、过拟合欠拟合的代码实现 :fire:①生成数据集②定义评估损失③定义训练函数④三阶多项式函数拟合⑤线性函数拟合(欠拟合)⑤高阶多项式函数拟合(过拟合) 十三、权…

【C语言】精品练习题

目录 题目一&#xff1a; 题目二&#xff1a; 题目三&#xff1a; 题目四&#xff1a; 题目五&#xff1a; 题目六&#xff1a; 题目七&#xff1a; 题目八&#xff1a; 题目九&#xff1a; 题目十&#xff1a; 题目十一&#xff1a; 题目十二&#xff1a; 题目十…

「 网络安全常用术语解读 」漏洞利用预测评分系统EPSS详解

1. 概览 EPSS&#xff08;Exploit Prediction Scoring System&#xff0c;漏洞利用预测评分系统&#xff09; 提供了一种全新的高效、数据驱动的漏洞管理功能。EPSS是一项数据驱动的工作&#xff0c;使用来自 CVE 的当前威胁信息和现实世界的漏洞数据。 EPSS 模型产生 0 到 1&…

vue 中的 Vuex

Vuex Vuex是什么&#xff1f; 概念&#xff1a;专门在vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff0c;对Vue应用中多个组件的共享状态进行集中式的管理(读/写&#xff09;&#xff0c;也是一种组件间通信的方式&#xff0c;且适用于任意组件间…

2024最新小红书电商落地实操课,从入门到精通,打造爆款方法(16节课)

你是不是经常在小红书上看到各种各样的推广和引流方法&#xff0c;却感觉实际操作起来很困难&#xff1f; 那么&#xff0c;这门2024最新小红书电商落地实操课就是为你量身定制的&#xff01;从入门到精通&#xff0c;不仅能让你了解电商平台的基本规则和玩法&#xff0c;还能…

ansible------inventory 主机清单

目录 inventory 中的变量 2&#xff09;组变量[webservers:vars] #表示为 webservers 组内所有主机定义变量&#xff0c;所有组内成 员都有效 ansible_userrootansible_passwordabc1234 3&#xff09; [all:vars…

[Java EE] 文件IO(一):文件概念与文件系统操作

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

Java RMI SERVER命令执行漏洞

Java RMI SERVER命令执行漏洞 一、介绍二、原理三、复现准备四、漏洞复现 一、介绍 RMI全称是Remote Method Invocation&#xff08;远程方法调用&#xff09;&#xff0c;是专为Java环境设计的远程方法调用机制&#xff0c;远程服务器提供API&#xff0c;客户端根据API提供相…

【3dmax笔记】020:变换输入、世界坐标、屏幕坐标案例详解

文章目录 一、变换输入二、世界坐标三、屏幕坐标四、区别一、变换输入 变换输入可用于:移动/旋转/缩放变换输入,快捷键为F12,在变换输入窗口中,有两种常见重要的坐标系: 世界坐标:固定屏幕坐标:随着选择的视图发生变化在3ds Max中,世界坐标(World Coordinate System)…

Git Bash和Git GUI设置中文的方法

0 前言 Git是一个分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。一般默认语言为英文&#xff0c;本文介绍修改Git Bash和Git GUI语言为中文的方法。 1 Git Bash设置中文方法 &#xff08;1&#xff09;鼠标右键&#xff0c;单击“Git B…

网络无线网卡无法配置正确的 dns 服务器

网络无线网卡无法配置正确的 dns 服务器--解决办法 网络无线网卡无法配置正确的 dns 服务器--解决办法 网络无线网卡无法配置正确的 dns 服务器–解决办法 建议先使用疑难反馈&#xff08;自带的&#xff09; 打开网络适配中心 之后更改适配器设置&#xff0c;在点击 wlan 属…