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

C++11--右值引用与移动语义

目录

基本概念

左值与右值

左值引用与右值引用

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

左值引用的使用场景

右值引用和移动语义

移动构造和拷贝构造的区别

编译器的优化

移动赋值和赋值运算符重载的区别

右值引用的其他应用场景

完美转发

万能引用

完美转发保持值属性

完美转发的使用场景


基本概念

左值与右值

什么是左值?

左值是一个表示数据的表达式,如:变量名或解引用的指针
它的两个特点
·我们可以获取它的地址也可以对它赋值(const修饰除外)

·左值既可以出现在表达式的左边也可以出现在表达式的右边

//可以取地址对象,就是左值
int main()
{int a = 10;int& r1 = a;int* p = &a;int& r2 = *p;const int b = 10;const int& r3 = b;return 0;
}

什么是右值?

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引
用返回)等等 
它的两个特点

·右值不能被取地址也不能被修改

·右值只能出现在表达式的右边不能出现在表达式左边

//不能取地址对象,就是右值
int main()
{double x = 1.1, y = 2.2;//常见的右值10;x + y;fmin(x, y);//cout << &fmin(x, y) << endl;return 0;
}

左值引用与右值引用

传统的C++语法中就有引用的语法,而在C++11中更新了右值引用的语法。为了进行区分,我们将C++11之前的引用叫做左值引用,将C++11之后更新的引用叫做右值引用,不论是左值引用还是右值引用,它们的本质都是 “取别名”。

左值引用

左值引用就是对于左值的引用,即对左值取别名,通过&来声明

下面是一段代码示例

// 以下的p b c *p都是左值
int* p = new int(0);
int b = 1;
const int c = 2;// 以下几个是对上面左值的左值引用
int*& rp = p;
int& rb = b;
const int& rc = c;
int& pv= *p;

右值引用

右值引用就是对右值的引用,即对右值取别名,通过&&来声明

下面是一段代码示例

//不能取地址对象,就是右值
int main()
{double x = 1.1, y = 2.2;//常见的右值10;x + y;fmin(x, y);//cout << &fmin(x, y) << endl;//右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);return 0;
}
需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可
以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地
址,也可以修改rr1.
如果不想rr1被修改,可以用const int&& rr1 去引用.
左值引用可以引用右值吗?
  • 左值引用不能引用右值,左值是可以被修改的而右值是不可以被修改的,这里涉及到一个权限放大的问题
  • 如果想要用左值引用来引用右值,需要用到const关键字来修饰左值引用,因为经过const修饰后左值引用就没有修改的权限了

因此const左值引用可以引用左值也可以引用右值

template<class T>
void func(const T& val)
{cout << val << endl;
}int main()
{string s("hello");func(s);                    //s为变量 左值func("world");              // "world"是常量 右值return 0;
}

右值引用可以引用左值吗?

  • 右值引用只能引用右值不能引用左值
  • 如果想要用右值引用来引用左值,需要用到move函数

move函数是C++11标准提供的一个函数,被move后的左值能够被右值引用引用

int main()
{//左值int* p = new int(0);int b = 1;const int c = 2;//左值引用能否引用右值 -- 不能直接引用,但是const左值引用可以引用右值//void push_back(const T& x)const int& r1 = 10;const double& r2 = x + y;const double& r3 = fmin(x, y);//右值引用能否引用左值 -- 不能直接引用,但是右值引用可以引用move以后左值int*&& rr1 = move(p);int&& rr2 = move(*p);int&& rr3 = move(b);const int&& rr4 = move(c);return 0;
}

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

虽然使用const修饰的左值引用能够同时引用左值和右值,但是左值引用终究是存在一些缺陷,而C++11提出的右值引用正是用来解决这些缺陷的

我们写出一个简单string类来

namespace qwe
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string(const char* str = ""):_size(strlen(str)), _capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}//s1.swap(s2)void swap(string& s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}//拷贝构造string(const string& s):_str(nullptr), _size(0), _capacity(0){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(){delete[] _str;_str = nullptr;}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;}string operator+(char ch){string tmp(*this);push_back(ch);return tmp;}const char* c_str() const{return _str;}private:char* _str;size_t _size;size_t _capacity;   };
}

左值引用的使用场景

在说明左值引用的缺陷之前我们先来看它的使用场景

  • 做参数--防止传参时进行拷贝构造
  • 做返回值--防止返回时对返回对象进行拷贝构造
void func1(shy::string s)
{}void func2(const shy::string& s)
{}int main()
{shy::string s("hello world");func1(s);                       func2(s);                        // 左值引用传参s += 'X';                        // 左值引用返回return 0; 
}

func1它传递的参数是形式参数,他是实际参数的一份临时拷贝

func2它传递的参数是s的别名,是左值引用

最后是+=,它返回的也是一份左值引用

string的拷贝是深拷贝,深拷贝的代价是很高的,所以说这里的左值引用效果很明显

左值引用的缺陷
左值引用虽然能避免不必要的拷贝操作 但是缺不能完全避免

左值引用做参数,能够完全避免传参时的拷贝操作
左值引用做返回值,不能完全避免函数对象返回时的拷贝操作
如果函数返回对象是一个局部变量,那么该变量出了局部作用域就会被销毁

这种情况下不能使用左值引用作为返回值,只能传值返回,这就是左值引用的短板

比如说我们实现一个to_string函数 将字符串转化为int类型 此时它的返回值就必须要是值拷贝 如果使用左值引用返回就会返回一个销毁的局部变量

代码表示如下

namespace qwe 
{string to_string(int value){bool flag = true;if (value < 0){flag = false;value = 0 - value;}string str;while (value > 0){int x = value % 10;value /= 10;str += (x + '0');}if (flag == false){str += '-';}std::reverse(str.begin(), str.end());return str;}
}

我们在调用to_string函数返回的时候会调用拷贝构造函数

C++11提出右值引用就是为了解决左值引用的这个缺陷,但是它的解决方法并不是单纯的将右值引用作为返回值

右值引用和移动语义

右值引用和移动语义解决上述问题的方式就是增加移动构造和移动赋值

移动构造

移动构造是一个构造函数 它的参数是右值引用类型

移动构造的本质就是将传入右值的资源转移过来 

代码表示如下

// 移动构造 
string(string&& s):_str(nullptr), _size(0), _capacity(0)
{cout << "string(string&& s)" << endl;swap(s);
}

移动构造和拷贝构造的区别:

在没有增加移动构造之前 由于拷贝构造使用的是const左值引用来接受参数 因此无论是左值还是右值 都会调用拷贝构造函数
增加移动构造之后 由于移动构造采用的是右值引用来接受参数 因此如果拷贝构造对象时传入的是右值 那么就会调用移动构造
 拷贝构造进行的是深拷贝 而移动构造只需要调用swap函数进行资源转移即可 因此移动构造的代价比拷贝构造的代价小很多
给string类增加移动构造之后 对于返回局部string类对象的函数 返回string类对象的时候会调用移动构造进行资源的转移 不会像原来一样进行深拷贝了

演示效果如下

对于to_string当中返回局部的string对象是一个左值 一个临时变量 由于它出了局部作用域就会被销毁 被消耗的值我们将它叫做 “将亡值” 匿名对象也可以被称为 “将亡值”,因此对待这种 “将亡值” 编译器会将它识别为右值 这样就可以匹配搭配参数为右值的移动构造函数

编译器的优化

当一个函数在返回局部对象时,会先用局部对象拷贝出一个临时对象,然后再用这个临时拷贝的对象来拷贝定义的对象

 对于深拷贝的类会进行两次深拷贝 但是大部分编译器为了提高效率都对这种情况进行了优化 优化成了一次深拷贝

效果图如下

如果不进行优化 这里应该会调用拷贝构造和移动构造
如果进行了优化 这里就只会进行一次移动构造了
但是我们如果不是用函数的返回值来构造出一个对象 而是用一个之前已经定义过的对象来接受函数的返回值 这里就无法进行优化了

示例图如下

        对于返回局部对象的函数 就算只是调用函数而不接收该函数的返回值 也会存在一次拷贝构造或移动构造 因为函数的返回值不管接不接收都必须要有 而当函数结束后该函数内的局部对象都会被销毁 所以就算不接收函数的返回值也会调用一次拷贝构造或移动构造生成临时对象

移动赋值

移动赋值是对于赋值运算符重载的一个重载函数 该函数的参数是右值引用类型

在当前的string类中增加一个移动赋值函数 就是调用swap函数将传入右值的资源窃取过来

代码表示如下

// 移动赋值
string& operator= (string && s)
{cout << "string& operatpr=(string&& s)" << endl;swap(s);return *this;
}

移动赋值和赋值运算符重载的区别

在没有增加移动赋值之前 赋值运算符重载是使用const左值引用来接受参数 无论传入的是左值还是右值 都会调用它
增加移动赋值之后 由于移动赋值采用的是右值引用来接受参数 因此如果移动赋值传入的是右值 那么就会调用移动赋值
原本赋值时是调用拷贝构造进行了深拷贝 而移动赋值只需要调用swap函数进行资源转移即可 因此移动赋值的代价比赋值运算符重载小的很多

STL中的容器

以string为例

移动构造

移动赋值

move函数

move函数它并不能移动过任何值 它的功能是将一个左值强制转化为右值引用 然后实现移动语义

move函数的定义如下

template<class _Ty>
inline typename remove_reference<_Ty>::type&& move(_Ty&& _Arg) _NOEXCEPT
{//forward _Arg as movablereturn ((typename remove_reference<_Ty>::type&&)_Arg);
}
  • move函数模板中_Arg参数的类型不是右值引用而是万能引用 万能引用和右值引用的形式一样 但是右值引用是需要确定的类型
  • 一个左值被move之后它的资源有可能被转移给别的数据了 所以说慎用被move后的左值

右值引用的其他应用场景

插入函数

 如果list中插入的对象类型是string

list<qwe::string> ls;
qwe::string s("1111");ls.push_back(s);                   // 拷贝构造ls.push_back("2222");              // 移动构造
ls.push_back(qwe::string("3333")); // 移动构造
ls.push_back(std::move(s));        // 移动构造
效果如下

完美转发

万能引用

模板中的&&不代表右值引用 而是万能引用 这样它既能接收左值又能接收右值 

template<class T>
void PerfectForward(T&& t)
{}

右值引用和万能引用的区别就是 右值引用需要确定类型 而万能引用会根据传入的类型进行推导 如果传入的实参是一个左值 那么这里的形参t就是左值引用 如果传入的实参是一个右值 那么这里的形参t就是右值引用

下面重载了四个func函数 这四个func函数的参数分别左值引用 const左值引用 右值引用和const右值引用

我们在主函数中使用完美引用模板函数来调用func函数

代码表示如下
 

void Fun(int &x){ cout << "左值引用" << endl; }
void Fun(const int &x){ cout << "const 左值引用" << endl; }void Fun(int &&x){ cout << "右值引用" << endl; }
void Fun(const int &&x){ cout << "const 右值引用" << endl; }void PerfectForward(int&& t)
{Fun(t);
}void PerfectForward(const int& t)
{Fun(t);
}int main()
{PerfectForward(10);           // 右值int a;PerfectForward(a);            // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b);		      // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}

不管传入何种类型 最后调用的都是左值引用而不是右值引用

因为只要右值经过一次引用之后右值引用就会被储存到特定位置 这个右值就可以被取地址和改 所以在经过一次参数传递之后右值就会退化为左值 如果我们想要让他保持右值的属性 这个时候就要用到完美转发

完美转发保持值属性

要想在参数传递过程中保持其原有的属性 需要在传参时调用forward函数

代码表示如下

//模板中的&& 表示万能引用,既能接收左值又能接收右值
//会退化成左值   --  完美转发  
template<typename T>
void PerFectForeard(T&& t)
{Fun(std::forward<T>(t));
}

完美转发的使用场景

下面提供一个简单的list类 分别提供了左值引用和右值引用的接口函数

	template<class T>struct ListNode{T _data;ListNode* _next = nullptr;ListNode* _prev = nullptr;};template<class T>class list{typedef ListNode<T> node;public://构造函数list(){_head = new node;_head->_next = _head;_head->_prev = _head;}//左值引用版本的push_backvoid push_back(const T& x){insert(_head, x);}//右值引用版本的push_backvoid push_back(T&& x){insert(_head, std::forward<T>(x)); //完美转发}//左值引用版本的insertvoid insert(node* pos, const T& x){node* prev = pos->_prev;node* newnode = new node;newnode->_data = x;prev->_next = newnode;newnode->_prev = prev;newnode->_next = pos;pos->_prev = newnode;}//右值引用版本的insertvoid insert(node* pos, T&& x){node* prev = pos->_prev;node* newnode = new node;newnode->_data = std::forward<T>(x); //完美转发prev->_next = newnode;newnode->_prev = prev;newnode->_next = pos;pos->_prev = newnode;}private:node* _head; //指向链表头结点的指针};

定义一个list对象 储存我们之前实现的list类 我们分别传入左值和右值调用不同版本的push_back函数

	qwe::list<qwe::string> lt;qwe::string s("1111");lt.push_back(s);           //调用左值引用版本的push_backlt.push_back("2222");      //调用右值引用版本的push_back

我们在实现push_back的时候复用了insert的代码 对于左值引用的insert函数来说 它会先new一个节点 然后将对应的左值赋值给这个节点 调用赋值运算符重载 又因为赋值运算符重载本质上复用了拷贝构造 
对于右值版本的push_back函数 它复用了insert的代码 对于右值引用的insert函数来说 它会先new一个节点 然后将对应的右值赋值给这个节点 调用移动构造来进行转移资源
这其中调用函数传参的时候多处用到了 完美转发 这是因为如果不使用完美转发就会让右值退化为左值 最终导致多一次深拷贝 从而降低效率
 
如果我们想要保持右值的属性 每次传参的时候就必须要使用完美转发

与STL中的list的区别

如果将刚才测试代码中的list换成STL当中的list

调用左值版本的push_back插入节点时 在构造结点时会调用string的拷贝构造函数
调用右值版本的push_back插入节点时 在构造结点时会调用string的移动构造函数
而我们实现的list代码却使用的是赋值运算符重载和移动赋值

这是因为我们是使用的new操作符来申请空间 new操作符申请空间之后会自动调用构造函数进行初始化

而初始化之后就只能使用赋值运算符重载了

而STL库中使用空间配置器获取内存 因此在申请到内存后不会调用构造函数对其进行初始化 是后续用左值或右值对其进行拷贝构造 所以会产生这样子的结果

如果我们想要达到STL中的效果 我们只需要使用malloc开辟空间 然后使用定位new进行初始化就可以了

相关文章:

C++11--右值引用与移动语义

目录 基本概念 左值与右值 左值引用与右值引用 右值引用的使用场景和意义 左值引用的使用场景 右值引用和移动语义 移动构造和拷贝构造的区别 编译器的优化 移动赋值和赋值运算符重载的区别 右值引用的其他应用场景 完美转发 万能引用 完美转发保持值属性 完美转…...

Python SQLAlchemy入门教程

本文将以Mysql举例&#xff0c;介绍sqlalchemy的基本用法。其中&#xff0c;Python版本为2.7&#xff0c;sqlalchemy版本为1.1.6。 一. 介绍 SQLAlchemy是Python中最有名的ORM工具。 关于ORM&#xff1a; 全称Object Relational Mapping&#xff08;对象关系映射&#xff0…...

你是真的“C”——操作符详解【下篇】+整形提升+算术转换

你是真的“C”——操作符详解下篇&#x1f60e;前言&#x1f64c;操作符详解【上篇】内容&#xff1a;操作符详解【下篇】内容&#xff1a;1、 条件操作符2、逗号表达式&#xff1a;3、下标引用、函数调用和结构成员3、访问一个结构的成员表达式求值1、隐式类型转换&#xff1a…...

文本匹配SimCSE模型代码详解以及训练自己的中文数据集

前言 在上一篇博客文本匹配中的示例代码中使用到了一个SimCSE模型&#xff0c;用来提取短文本的特征&#xff0c;然后计算特征相似度&#xff0c;最终达到文本匹配的目的。但是该示例代码中的短文本是用的英文短句&#xff0c;其实SimCSE模型也可以用于中文短文本的特征提取&a…...

Biotin-PEG-FITC 生物素聚乙二醇荧光素;FITC-PEG-Biotin 科研用生物试剂

结构式&#xff1a; ​Biotin-PEG-FITC 生物素聚乙二醇荧光素 英文名称&#xff1a;Biotin-PEG-Fluorescein 中文名称&#xff1a;生物素聚乙二醇荧光素 外观&#xff1a;黄色液体、半固体或固体&#xff0c;取决于分子量。 溶剂&#xff1a;溶于大部分有机溶剂&#xff0c;…...

FISCO BCOS 搭建区块链,在SpringBoot中调用合约

一、搭建区块链 使用的是FISCO BCOS 和 WeBASE-Front来搭建区块链&#xff0c;详细教程&#xff1a; https://blog.csdn.net/yueyue763184/article/details/128924144?spm1001.2014.3001.5501 搭建好能达到下图效果即可&#xff1a; 二、部署智能合约与导出java文件、SDK证…...

面试官:int和Integer有什么区别?

回答思路&#xff1a; 原始数据类型和包装类介绍 主要区别&#xff08;数据使用内存&#xff09; 自动装箱、自动拆箱机制和实践原则 回答总结&#xff1a; int 是8种基本数据类型&#xff08;byte、boolean、char、short、int、long、float、double&#xff09;之一&#xff…...

MFC常用技巧

MFC常用技巧1、句柄MFC中如何获取窗口的句柄2、字符串CString转char*Unicode下char *转换为CString3、Visual C 64 位迁移的常见问题&#xff08;数据类型、指针类型的长度问题&#xff09;4、c - 将_beginthread返回的uintptr_t转换为HANDLE是否安全1、句柄 MFC中如何获取窗口…...

C++ —— 多态

目录 1.多态的概念 2.多态的定义及实现 2.1构成多态的两个硬性条件 2.2虚函数的重写 2.3override和final 3.抽象类 3.1接口继承和实现继承 4.多态原理 4.1虚函数表 4.2原理 4.3静态绑定和动态绑定 5.单继承和多继承体系的虚函数表 5.1单继承体系的虚函数表 5.2多继…...

java agent设计开发概要

agent开发设计 agent 开发的一些心得&#xff0c;适合熟悉agent或者有agent开发需求的同学 1 有个基础的agent&#xff0c;是java 标准的agent。这是agent代码入口 2 设计包结构&#xff0c; 基础agent agent下有plugin,加载plugin可以自己定义一个类加载器 plugin&#xff1…...

node.js笔记-模块化(commonJS规范),包与npm(Node Package Manager)

目录 模块化 node.js中模块的分类 模块的加载方式 模块作用域 向外共享模块作用域中的成员 向外共享成员 包与npm&#xff08;Node package Manager&#xff09; 什么是包&#xff1f; 包的来源 为什么需要包&#xff1f; 查找和下载包 npm下载和卸载包命令 配置np…...

Linux 磁盘坏块修复处理(错误:read error: Input/output error)

当磁盘出现坏块时&#xff0c;你对所关联的文件进行读取时&#xff0c;一般会出现 read error: Input/output error 这样的错误。 反过来讲&#xff0c;当你看到 read error: Input/output error 这种错误时&#xff0c;很大可能就是磁盘出现了坏块问题。 解决步骤&#xff1a…...

API 面试四连杀:接口如何设计?安全如何保证?签名如何实现?防重如何实现?

下面我们就来讨论下常用的一些API设计的安全方法&#xff0c;可能不一定是最好的&#xff0c;有更牛逼的实现方式&#xff0c;但是这篇是我自己的经验分享. 一、token 简介 Token&#xff1a;访问令牌access token, 用于接口中, 用于标识接口调用者的身份、凭证&#xff0c;减…...

操作系统题目收录(六)

1、某系统采用基于优先权的非抢占式进程调度策略&#xff0c;完成一次进程调度和进程切换的系统时间开销为1us。在T时刻就绪队列中有3个进程P1P_1P1​、P2P_2P2​和P3P_3P3​&#xff0c;其在就绪队列中的等待时间、需要的CPU时间和优先权如下表所示。若优先权值大的进程优先获…...

2023年十款开源测试开发工具推荐!

今天为大家奉献一篇测试开发工具集锦干货。在本篇文章中&#xff0c;将给大家推荐10款日常工作中经常用到的测试开发工具神器&#xff0c;涵盖了自动化测试、性能压测、流量复制、混沌测试、造数据等。 1、AutoMeter-API 自动化测试平台 AutoMeter 是一款针对分布式服务&…...

MySQL慢查询分析和性能优化

1 背景我们的业务服务随着功能规模扩大&#xff0c;用户量扩增&#xff0c;流量的不断的增长&#xff0c;经常会遇到一个问题&#xff0c;就是数据存储服务响应变慢。导致数据库服务变慢的诱因很多&#xff0c;而RD最重要的工作之一就是找到问题并解决问题。下面以MySQL为例子&…...

C++学习笔记(四)

组合、继承。委托&#xff08;类与类之间的关系&#xff09; 复合 queue类里有一个deque&#xff0c;那么他们的关系叫做复合。右上角的图表明复合的概念。上图的特例表明&#xff0c;queue中的功能都是通过调用c进行实现&#xff08;adapter&#xff09;。 复合关系下的构造和…...

【4】深度学习之Pytorch——如何使用张量处理时间序列数据集(共享自行车数据集)

表格数据 表格中的每一行都独立于其他行&#xff0c;他们的顺序页没有任何关系。并且&#xff0c;没有提供有关行之前和行之后的列编码信息。 表格类型的数据是指通过表格的形式表示的数据&#xff0c;它以行和列的方式组织数据。表格中的每一行代表一个数据项&#xff0c;每…...

mulesoft MCIA 破釜沉舟备考 2023.02.10.01

mulesoft MCIA 破釜沉舟备考 2023.02.10.01 1. What is a defining charcateristic of an integration-Platform-as-a-Service(iPaaS)?2. An application deployed to a runtime fabric environment with two cluster replicas is designed to periodically trigger of flow f…...

干货 | PCB拼板,那几条很讲究的规则!

拼板指的是将一张张小的PCB板让厂家直接给拼做成一整块。一、为什么要拼板呢&#xff0c;也就是说拼板的好处是什么&#xff1f;1.为了满足生产的需求。有些PCB板太小&#xff0c;不满足做夹具的要求&#xff0c;所以需要拼在一起进行生产。2.提高SMT贴片的焊接效率。只需要过一…...

笔试题-2023-思远半导体-数字IC设计【纯净题目版】

回到首页:2023 数字IC设计秋招复盘——数十家公司笔试题、面试实录 推荐内容:数字IC设计学习比较实用的资料推荐 题目背景 笔试时间:2022.08.20应聘岗位:数字IC设计工程师笔试时长:90min笔试平台:牛客网题目类型:填空题(2道),不定项选择题(3道),单选题(2道),问…...

canvas根据坐标点位画图形-canvas拖拽编辑单个图形形状

首先在选中图形的时候需要用鼠标右击来弹出选择框&#xff0c;实现第一个编辑节点功能 在components文件夹下新建右键菜单 RightMenu文件&#xff1a; <template><div v-show"show" class"right-menu" :style"top:this.ypx;left:this.xpx…...

JavaEE 初阶 — 确认应答机制

文章目录确认应答机制&#xff08;安全机制&#xff09;1 什么是后发先至问题1 如何解决后发先至问题确认应答机制&#xff08;安全机制&#xff09; 确认应答 是实现可靠传输的最核心机制。 这里指的 可靠传输 不是说 100% 可以把消息发给接收方&#xff0c;而是尽力而为&…...

0207 事件

事件监听事件监听版本事件类型事件概念事件在编程时系统内发生的动作或者发生的事情例子点击按钮鼠标经过拖拽鼠标事件监听&#xff08;注册事件&#xff0c;绑定事件&#xff09;让程序员检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立即调用一个函数做出响应…...

SpringBoot整合Swagger

目录 一、swagger介绍 二、springboot集成swagger 1、创建一个springboot-web项目 2、导入相关依赖 3、编写一个Hellow工程 4、配置swagger --->config 5、启动springboot工程 6、配置swagger信息 7、配置swagger扫描接口 8、如何设置Swagger在生产环境中使用&…...

20230210英语学习

Why Do So Many Cats Have White ‘Socks’ on Their Paws? 为什么好多猫咪脚上都“穿着白袜子”&#xff1f; If you see a house cat, the odds are high that it will have white paws, a look that many owners affectionately call "socks."But socks are rar…...

【图像处理OpenCV(C++版)】——4.5 全局直方图均衡化

前言&#xff1a; &#x1f60a;&#x1f60a;&#x1f60a;欢迎来到本博客&#x1f60a;&#x1f60a;&#x1f60a; &#x1f31f;&#x1f31f;&#x1f31f; 本专栏主要结合OpenCV和C来实现一些基本的图像处理算法并详细解释各参数含义&#xff0c;适用于平时学习、工作快…...

2022年API安全研究报告

目录 导读 2022年API安全风险概况 2022年平均每月遭受攻击的API数量超21万...

【内网安全-横向移动】基于SMB协议-PsExec

目录 一、SMB协议 1、简述&#xff1a; 2、工具&#xff1a; 二、PsExec 1、简述&#xff1a; 2、使用&#xff1a; 1、常用参数&#xff1a; 2、情况&#xff1a; 3、插件 三、PsExec&#xff08;impacket&#xff09; 1、简述&#xff1a; 1、impacket&#xff1…...

whistle 一个神奇的前端调试工具(抓包\代理工具)

在进行前端开发过程中&#xff0c;我们常常需要对一些接口进行处理&#xff0c;以及当后端接口没有弄好需要我们mock一些假数据&#xff0c;针对这些场景&#xff0c;我们就可以使用whistle 来解决。首先&#xff0c;我们要知道能满足我们需求的工具有很多&#xff0c;例如&…...

帮人做网站收费合法吗/网店无货源怎么做

文 | 曾响铃 来源 | 科技向令说&#xff08;xiangling0815&#xff09; 比尔盖茨说过&#xff0c;没有人相信“潜力”这东西&#xff0c;除非你做出一些事情来证明它。 在移动互联网时代&#xff0c;丛林般的APP构建起一座座信息孤岛&#xff0c;PC端的搜索引擎入口逐渐式微…...

如何自己做资源类网站/免费b站推广软件

直播地址&#xff1a;http://www.itdks.com/eventlist/detail/1876...

网页设计网站模板网站建设网页模板下载/高端建站

更多风控建模、大数据分析等内容请关注公众号《bigdatafengkong》 在对变量分箱后&#xff0c;需要计算变量的重要性&#xff0c;IV是评估变量区分度或重要性的统计量之一&#xff0c;R语言计算IV值的代码如下&#xff1a; CalcIV <- function(df_bin, key_var, y_var){N_0&…...

给我一个免费看片高清在线/怎样优化关键词到首页

一. adb 相关命令&#xff1a; 1. 关闭adb服务&#xff1a;adb kill-server 2. 启动adb服务 adb start-server 3. 查询当前运行的所有设备 adb devices 4. 可能在adb中存在多个虚拟设备运行 可以指定虚拟设备运行 -s 虚拟设备名称 5. 重启设备 adb reboot --指定虚拟设备 adb -…...

怎么弄自己的网站卖东西/如何找到网络公关公司

切片 取list或者tuple中的部分元素采用切片操作。 在list中取前N个元素&#xff0c;也就是索引为0-(N-1)的元素&#xff0c;可以用循环&#xff1a; >>> r []>>> n 3>>> for i in range(n):... r.append(L[i])... >>> r[Michael, Sa…...

wordpress小工具制作/网页怎么制作

背景 XX换工作了&#xff0c;入职了一家互联网公司 入职一周&#xff0c;XX经过了新员工培训、项目培训、产品培训、项目经理规范培训后&#xff0c;开始投入到项目管理工作。 领导给XX安排的任务是&#xff0c;独自负责公司的一个项目。 虽然有前辈的指导&#xff0c;但是…...