【C++】C++新增特性解析:Lambda表达式、包装器与绑定的应用

在这里插入图片描述

V可变参数模板与emplace系列

C++语法相关知识点可以通过点击以下链接进行学习一起加油!
命名空间缺省参数与函数重载C++相关特性类和对象-上篇类和对象-中篇
类和对象-下篇日期类C/C++内存管理模板初阶String使用
String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与QueuePriority Queue与仿函数
模板进阶-模板特化面向对象三大特性-继承机制面向对象三大特性-多态机制STL 树形结构容器二叉搜索树
AVL树红黑树红黑树封装map/set哈希-开篇闭散列-模拟实现哈希
哈希桶-模拟实现哈希哈希表封装 unordered_map 和 unordered_setC++11 新特性:序章右值引用、移动语义、万能引用实现完美转发可变参数模板与emplace系列

大家好,我是店小二。在这篇文章中,我们将深入探讨C++11的新特性——Lambda表达式、包装器与绑定的应用。如果在阅读过程中有不清楚的地方或发现任何错误,欢迎随时私信交流探讨。

请添加图片描述
Alt
🌈个人主页:是店小二呀
🌈C语言专栏:C语言
🌈C++专栏: C++
🌈初阶数据结构专栏: 初阶数据结构
🌈高阶数据结构专栏: 高阶数据结构
🌈Linux专栏: Linux

🌈喜欢的诗句:无人扶我青云志 我自踏雪至山巅 请添加图片描述

文章目录

  • 一、lambda表达式
    • 1.1 lambda表达式说明
    • 1.2 可省略部分
    • 1.3 lambda使用场景(个人推荐使用第二种)
    • 1.4 比较lambda和仿函数
    • 1.5 lambda类型
      • 1.5.1 未定义类型
      • 1.5.2 定义类型
    • 1.6 捕获列表
      • 1.6.1 捕获列表说明
      • 1.6.2 什么情况下捕捉列表必须为空?
      • 1.6.3 传值捕捉
      • 1.6.4 mutable可以修改拷贝对象
      • 1.6.5 引用捕获
      • 1.6.6 传值捕捉所有对象
      • 1.6.7 传引用捕捉所有对象
      • 1.6.8 混合捕捉
    • 1.7 函数对象与lambda表达式
  • 二、包装器
    • 1.1 function包装器
    • 1.2 function使用场景(对上面的修改)
  • 三、bind绑定
    • 3.1 bind概念
    • 3.2 placeholders

一、lambda表达式

在C++98中,如果想要对一个数据集合中的元素进行排序,可以使用std::sort方法 。

struct Goods
{string _name;double _price;int _evaluate;Goods(const char* str, double price, int evaluate):_name(str),_price(price),_evaluate(evaluate){}
};struct ComparePriceLess
{bool operator()(const Goods& gl, const Goods& gr){return gl._price < gr._price;}
};
struct ComparePriceGreater
{bool operator()(const Goods& gl, const Goods& gr){return gl._price > gr._price;}
};
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());
}

随着C++语法的发展,上面的写法过于复杂,每次为了实现一个algorithm算法,都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,这些都给编程者带来了极大的不便。因此,在C++11语法中出现了Lambda表达式 (本质也是匿名对象调用仿函数)

1.1 lambda表达式说明

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

lambda表达式各部分说明:

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

1.2 可省略部分

在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。

因此C++11中最简单的lambda函数为:[]{}表示lambda函数不能做任何事情

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

int main()
{//lambdaauto add1 = [](int a, int b)->int {return a + b; };//返回值 可以省略auto add2 = [](int a, int b) {return a + b; };//没有参数,参数列表可以省略auto func1 = [] {cout << "hello world" << endl; };//调用lambda匿名函数cout << add1(1, 2) << endl;func1();return 0;
}

1.3 lambda使用场景(个人推荐使用第二种)

在这里插入图片描述

//第一种
auto ComparePriceGreater = [](const Goods& gl, const Goods& gr) { return gl._price > gr._price;});
sort(v.begin(), v.end(),ComparePriceGreater);//第二种
sort(v.begin(), v.end(), [](const Goods& gl, const Goods& gr) { return gl._price > gr._price;});

1.4 比较lambda和仿函数

  • 功能:仿函数和 Lambda 表达式都能重新定义函数调用的行为,但是 Lambda 表达式更加灵活和直观,特别是在需要定义简短、一次性的函数时非常方便
  • 语法:Lambda 表达式的语法更为紧凑,使得代码更易于阅读和维护,而仿函数则更适合于需要长期保存状态或多次调用的情况。
  • 使用场景:在现代 C++ 中,Lambda 表达式通常更受欢迎,因为它们简洁明了,且能够直接在需要时定义和使用,避免了定义额外的类或结构体。

上述代码就是使用C++11中lambda表达式来解决,可以看出lambda表达式实际是一个匿名函数。既然是匿名函数lambda的类型也是不得而知的,但是我们可以通过cout << typeid().name << endl;参考下类型

1.5 lambda类型

Lambda 表达式在 C++ 中的类型可以有两种主要形式:*未命名类型和命名类型

1.5.1 未定义类型

当 Lambda 表达式没有被赋予一个变量或者没有作为参数传递给一个模板时,它们是未命名的,也就是没有特定的类型,对象的行为是函数体和函数参数决定的未命名类型的 Lambda 表达式auto lambda = [](int x){return x * 2;};

在这里插入图片描述

1.5.2 定义类型

当 Lambda 表达式被赋予一个变量或者被用作模板参数时,它们可以有一个具体的类型命名类型的 Lambda 表达式:std::function<int(int)> lambda = [](int x) { return x * 2; };

在这里插入图片描述

lambda原理类似范围for。lambda编译时,编译器会生成对应仿函数的名称,对此lambda本质还是仿函数

在这里插入图片描述

1.6 捕获列表

1.6.1 捕获列表说明

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

  • [var]:表示值传递方式捕捉变量var
  • [=]:表示值传递方式捕获所有父作用域中的变量(包括this)
  • [&var]:表示引用传递捕捉变量var
  • [&]:表示引用传递捕捉所有父作用域中的变量(包括this)
  • [this]:表示值传递方式捕捉当前的this指针

捕获列表注意:

  1. 父作用域指包含lambda函数的语句块
  2. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
  3. 捕捉列表不允许变量重复传递,否则就会导致编译错误。比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复
  4. 在块作用域以外的lambda函数捕捉列表必须为空。
  5. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错
  6. lambda表达式之间不能相互赋值,即使看起来类型相同

1.6.2 什么情况下捕捉列表必须为空?

如果一个lambda函数被定义在某个块作用域内,而它试图在这个块作用域外部(即在这个块结束后)使用,这时这个lambda函数的捕捉列表必须为空。原因是:

  • 捕捉的变量作用域有限:在块作用域结束后,块作用域内的局部变量将不再存在。如果lambda函数捕捉了这些变量,并在块外部被调用,这会导致未定义行为,因为那些变量已经销毁了。
  • 捕捉列表为空:意味着lambda函数不依赖于块作用域中的任何局部变量,这样lambda函数就可以在块作用域结束后安全地使用。

块作用域:这是一个局部作用域,通常指在花括号 {} 中的代码块,比如函数体或循环体。

以上是相关捕获列表的相关知识,以下将通过代码进行分析,深入理解使用。

1.6.3 传值捕捉

第一种:捕获a,b对象给lambda,但是不可以修改捕获对象,因为这里捕获a,b对象是对外面域a,b对象的拷贝,临时对象具有常性

int main()
{int a = 10, b = 20;cout << "a: " << a << "   " << "b: " << b << endl;auto swap = [a, b]() {int tmp = a;a = b;b = tmp;};swap();cout << "a: " << a << "   " << "b: " << b << endl;return 0;
}

在这里插入图片描述

1.6.4 mutable可以修改拷贝对象

mutable可以修改传值捕捉对象(日常一般不需要),因为这里捕获a,b对象是对外面域a,b对象的拷贝,虽然修改也不改变外面的a b。

int main()
{int a = 10, b = 20;cout << "a: " << a << "   " << "b: " << b << endl;auto swap = [a, b]() mutable{int tmp = a;a = b;b = tmp;};swap();cout << "a: " << a << "   " << "b: " << b << endl;return 0;
}

在这里插入图片描述

1.6.5 引用捕获

int main()
{int a = 10, b = 20;cout << "a: " << a << "   " << "b: " << b << endl;auto swap = [&a,&b]() {int tmp = a;a = b;b = tmp;};swap();cout << "a: " << a << "   " << "b: " << b << endl;return 0;
}

在这里插入图片描述

1.6.6 传值捕捉所有对象

int main()
{int a = 1, b = 2, c = 3, d = 4, e = 5;// 传值捕捉所有对象auto func1 = [=](){return a + b + c * d;};cout << func1() << endl;return 0;
}

1.6.7 传引用捕捉所有对象

int main()
{int a = 1, b = 2, c = 3, d = 4, e = 5;auto func = [&](){a++;b++;c++;d++;e++;};func();cout << a << b << c << d << e << endl;return 0;
}

1.6.8 混合捕捉

auto func3 = [&, d, e]()
{a++;b++;c++;d++;e++;
};func3();
cout << a << b << c << d << e << endl;

以上虽然有什么传值捕获、引用捕获、混合捕获,其实只要调用函数传值感觉差不多,这里重点是掌握用法就行了

1.7 函数对象与lambda表达式

函数对象又称为仿函数,即可以想函数一样使用的对象,就是在类中重载了operator()运算符的类对象

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);// lamberauto r2 = [=](double monty, int year)->double {return monty * rate * year;};r2(10000, 2);return 0;
}

从使用方式上来看,函数对象与lambda表达式完全一样,函数对象将rate作为其成员变量,在定义对象时给出初始值即可,lambda表达式通过捕获列表可以直接将该变量捕获到。

在这里插入图片描述

实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()

二、包装器

//可调用对象  -- 使用了模板
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 f(double i)
{return  i / 2;}struct Functor
{double operator()(double d){return d / 3;}
};int main()
{//函数名cout << useF(f, 11.11) << endl;//函数对象(这里是匿名对象)cout << useF(Functor(), 11.11) << endl;//lambda表达式(利用模板)cout << useF([](double d)->double {return d / 4; }, 11.11) << endl;return 0;
}

通过模板根据不同的类型可以调用不同的可调用对象,比如函数指针、仿函数对象、lambda,如此繁多的选择也可能会导致模板效率低下。通过上面的程序验证,这里useF函数模板实例化了三份,而且对于不同的可调用对象也有存在于自己的缺点和优点,这里就需要包装器进行统一下了。

可调用对象优缺点分析:

  • 函数指针 --> 类型定义复杂
  • 仿函数对象 --> 要定义一个类,用的时候有点麻烦,不适合统一类型
  • lambda --> 没有类型概念(类型对我们没有用)

在这里插入图片描述

1.1 function包装器

function包装器也叫作适配器C++中的function本质是一个类模板,也是一个包装器。std::function在头文件。

function类模板原型

template <class T>  function; // undefindtemplate <class Ret, class... Args>
class function<Ret(Args...)>;模板参数说明:Ret : 被调用函数的返回类型Args…:被调用函数的形参

function不是定义可调用对象,而是包装可调用对象

function<int(int,int)> fc1;↑      ↑返回值类型  形参类型列表

1.2 function使用场景(对上面的修改)

#include <functional>
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 f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};
int main()
{// 函数名std::function<double(double)> func1 = f;cout << useF(func1, 11.11) << endl;// 函数对象std::function<double(double)> func2 = Functor();cout << useF(func2, 11.11) << endl;// lamber表达式std::function<double(double)> func3 = [](double d)->double { return d / 4; };cout << useF(func3, 11.11) << endl;return 0;
}

通过以上代码,可以更好地去了解包装可调用对象,达到统一的作用。不妨在看一个场景。

在这里插入图片描述

主要是看红色框起来的地方跟左边代码对比,其实逻辑是大致相同,如果遇到操作符进行对应的运算,左边是通过switch分支语句实现,右边则是通过map的kv模型,将对于运算符(这里是字符)和包装器联系在一起,而包装器是对可调用对象进行包装,保证了不同的操作符对应不同仿函数的逻辑。然后下面返回仿函数直接调用就行了。将可调用函数跟数值联系起来并且存储在map类中。

三、bind绑定

3.1 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);

可以将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来"适应"原对象的参数列表

调用bind的一般形式:auto newCallable ==bind(callable,arg_list);

参数部分:

  1. newCallable本身是一个可调用对象
  2. arg_list是一个逗号分隔的参数列表,对应给定的callable的参数

当我们调用newCallable时,neweCallable会调用callable,并传给它arg_list中的参数。

3.2 placeholders

在这里插入图片描述

arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是"占位符",表示newCallable的参数的"位置"。数值n表示n生成的可调用对象中参数的位置: _1未newCallable的第一个参数, _2为第二个参数。以此类推。

在这里插入图片描述

std::placeholders::_1std::placeholders::_2 等是 C++11 标准引入的占位符,用于绑定函数对象时表示参数的位置。它们依次表示函数的第一个、第二个、第三个参数,以此类推。

在这里插入图片描述

std::bind 这里绑定了 fx 函数的第一个参数 s 为字符串 name(即“王昭君”),并将第二个参数和第三个参数的位置分别用 _1_2 来占位。这意味着生成的 f 是一个新的可调用对象,它接受两个参数,分别用于 fx 的第二个参数 x 和第三个参数 y

std::placeholders::_1_2 指定了新函数对象 f 的参数传递到原函数 fx 的对应位置,分别表示第二个和第三个参数位置。


在这里插入图片描述

以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二呀C++笔记,希望对你在学习C++语言旅途中有所帮助!

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

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

相关文章

HTB:Chatterbox[WriteUP]

目录 Connect to the HackTheBox server and spawn target machine Infomation Collection Use Rustscan to perform oepn scanning on the TCP port of the target Use Nmap to perform script and service scanning on the TCP port of the target Use Curl accessing p…

远程视频验证如何改变商业安全

如今&#xff0c;商业企业面临着无数的安全挑战。尽管企业的形态和规模各不相同——从餐厅、店面和办公楼到工业地产和购物中心——但诸如入室盗窃、盗窃、破坏和人身攻击等威胁让安全主管时刻保持警惕。 虽然传统的监控摄像头网络帮助组织扩大了其态势感知能力&#xff0c;但…

【C++】static修饰的“静态成员函数“--静态成员在哪定义?静态成员函数的作用?

声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff1b;用 static修饰的成员函数&#xff0c;称之为静态成员函数。静态成员变量一定要在类外进行初始化 一、静态成员变量 1)特性 所有静态成员为所有类对象所共…

Springboot捕获全局异常:MethodArgumentNotValidException

1.控制器 方法上添加Valid注解 PostMapping("/update")RequiresPermissions("user:update")public R update(RequestBody Valid UserEntity user) {userService.update(user);return R.ok();}2.实体类 public class UserEntity implements Serializable …

C#面向对象,封装、继承、多态、委托与事件实例

一&#xff0e;面向对象封装性编程 创建一个控制台应用程序&#xff0c;要求&#xff1a; 1&#xff0e;定义一个服装类&#xff08;Cloth&#xff09;&#xff0c;具体要求如下 &#xff08;1&#xff09;包含3个字段&#xff1a;服装品牌&#xff08;mark&#xff09;,服装…

【springboot】读取外部的配置文件

【springboot】读取外部的配置文件 一、使用场景二、代码实现&#xff08;一&#xff09;application.yml 的配置&#xff08;二&#xff09;编辑 customer.yml&#xff08;三&#xff09;自定义方法读取外部配置文件&#xff08;四&#xff09;使用外部配置文件的配置 一、使用…

解锁 Vue 项目中 TSX 配置与应用简单攻略

在 Vue 项目中配置 TSX 写法 在 Vue 项目中使用 TSX 可以为我们带来更灵活、高效的开发体验&#xff0c;特别是在处理复杂组件逻辑和动态渲染时。以下是详细的配置步骤&#xff1a; 一、安装相关依赖 首先&#xff0c;我们需要在命令行中输入以下命令来安装 vitejs/plugin-v…

游戏引擎学习第22天

移除 DllMain() 并成功重新编译 以下是对内容的详细复述与总结&#xff1a; 问题和解决方案&#xff1a; 在编译过程中遇到了一些问题&#xff0c;特别是如何告知编译器不要退出程序&#xff0c;而是继续处理。问题的根源在于编译过程中传递给链接器的参数设置不正确。原本尝试…

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象&#xff0c;使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令&#xff0c;如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令&#xff08;抽象类&#xff09; public abstract class …

QT6学习第四天 感受QT的文件编译

QT6学习第四天 感受QT的文件编译 使用纯代码编写程序新建工程 使用其他编辑器纯代码编写程序并在命令行运行使用 .ui 表单文件生成界面使用自定义 C 窗口类使用现成的QT Designer界面类 使用纯代码编写程序 我们知道QT Creator中可以用拖拽的方式在 .ui 文件上布局&#xff0c…

【SpringBoot】28 API接口防刷(Redis + 拦截器)

Gitee仓库 https://gitee.com/Lin_DH/system 介绍 常用的 API 安全措施包括&#xff1a;防火墙、验证码、鉴权、IP限制、数据加密、限流、监控、网关等&#xff0c;以确保接口的安全性。 常见措施 1&#xff09;防火墙 防火墙是网络安全中最基本的安全设备之一&#xff0c…

4——单页面应用程序,vue-cli脚手架

单页面应用程序(英文名:Single Page Application)简称 SPA,顾名 思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。 1、脚手架 ① 什么是脚手架 vue-cli 是 Vue.js 开发的标准工具&#xff61;它简化了程序员基于 webpack …

小程序 - 个人简历

为了让招聘人员快速地认识自己&#xff0c;可以做一个“个人简历”微信小程序&#xff0c; 展示自己的个人信息。 下面将对“个人简历”微信小程序进行详细讲解。 目录 个人简历 创建图片目录 页面开发 index.wxml index.wxss 功能实现截图 总结 个人简历 创建图片目录…

BUUCTF—Reverse—helloword(6)

一道安卓逆向的签到题 下载附件 使用JADX-gui反编译工具打开&#xff08;注意配环境&#xff09;&#xff0c;找到主函数 jadx 本身就是一个开源项目&#xff0c;源代码已经在 Github 上开源了 官方地址&#xff1a;GitHub - skylot/jadx: Dex to Java decompiler 发现flag …

单点登录深入详解之设计方案总结

基于cookie的单点登录解决方案 概述 用户登录之后 , 将认证信息存储至 Cookie &#xff0c;当再次访问本服务或者访问其他应用服务时&#xff0c;直接从 Cookie 中传递认证信息&#xff0c;进行鉴权处理。 问题 1. 如何保障Cookie内用户认证信息的安全性? 第一, Cookie…

JSONArray 与Object 之间的转换

PageResult<JSONArray> pageResult new PageResult<>();// 查出来的数据 JSONArray resultArray new JSONArray(); ject data new JSONObject();data.put("code", code); resultArray.add(data);// 将resultArray数据放入JSONArray,不是再包装成一个 …

cangjie (仓颉) vscode环境搭建

sdk下载 下载中心-仓颉编程语言官网 可选择半年更新版&#xff0c;不用申请。目前版本&#xff1a;0.53.13 &#xff0c;选择不同平台压缩包下载解压到任意位置即可 补充下载&#xff0c;vscode插件解压后&#xff0c;在vscode扩展中选择从vsix安装&#xff0c;安装后新增名为…

SmartSQL:一款方便、快捷的数据库文档查询、导出工具

&#x1f6a9; 项目介绍 SmartSQL 是一款方便、快捷的数据库文档查询、导出工具&#xff01;从最初仅支持SqlServer数据库、CHM文档格式开始&#xff0c;通过不断地探索开发、集思广益和不断改进&#xff0c;又陆续支持Word、Excel、PDF、Html、Xml、Json、MarkDown等文档格式…

IT监控 | Oracle云监控全解析

Oracle云(Oracle Cloud)是Oracle公司提供的云服务平台&#xff0c;涵盖了IaaS、PaaS、SaaS和DaaS&#xff0c;支持企业在云中构建、部署、集成和扩展应用&#xff0c;为企业提供了管理服务器、应用程序、存储、网络和数据中心的全面控制能力。 跟踪Oracle云基础设施的关键组件将…

攻防世界-web ics-06 [解法思路]

进入环境 点击左边的列表只有报表中心有反应 注意看url直接就是index.php?id1 我先试了sqlmap不行&#xff0c;然后就沉淀了一下 想到了id后面的参数问题&#xff0c;我谁便改了几个数都没反应 就想着用bp抓包爆一下这个参数&#xff0c;用了一个数字10000的字典 发现2333…