【C++】C++11——右值引用和移动语义、左值引用和右值引用、右值引用使用场景和意义、完美转发、新的类功能
文章目录
- C++11
- 5.右值引用和移动语义
- 5.1左值引用和右值引用
- 5.2左值引用与右值引用比较
- 5.3右值引用使用场景和意义
- 5.4右值引用引用左值及其一些更深入的使用场景分析
- 5.5完美转发
- 6.新的类功能
C++11
5.右值引用和移动语义
右值引用是C++11引入的一个新特性,用于支持移动语义和完美转发。
在C++中,左值和右值是根据它们在表达式中的位置来定义的。左值是指在表达式中位于赋值符号左侧的对象,而右值是指位于赋值符号右侧的对象。例如,在表达式 a = b 中,a 是左值,b 是右值。
在C++11之前,左值和右值都是使用普通的引用(T&)来处理的。但是,这在处理某些情况时会造成一些不便,例如在实现移动构造函数和移动赋值运算符时。
为了解决这个问题,C++11引入了右值引用(T&&)的概念。右值引用是一种特殊的引用类型,只能绑定到右值上。这使得我们可以实现移动语义,即将资源从一个对象移动到另一个对象,而不是进行深拷贝。
右值引用还可以用于实现完美转发,即在函数模板中将参数以原样传递给其他函数,保持其原始的左值或右值性质不变。这需要使用 std::forward 函数来实现。
5.1左值引用和右值引用
什么是左值什么是右值?
左值和右值是根据它们在表达式中的位置来定义的。
左值是指可以位于赋值符号左侧的对象,它表示一个对象的身份(例如,一个具有名称的变量)。左值必须在内存中有实体,可以使用取地址符&获取其地址。
右值指的是位于赋值符号右侧的对象,它表示一个对象的值。右值可以是临时对象(临时变量),也可以是在内存或CPU寄存器中的值。当一个对象被用作右值时,使用的是它的内容(值),而不是它的身份。
简单来说,左值和右值的区别在于:左值表示一个对象的身份,而右值表示一个对象的值。左值可以取地址,右值不能取地址。
左值示例:
int a = 10; // a 是左值,因为它是一个具有名称的变量,可以在赋值符号左侧使用
int b = a; // a 是左值,因为它在赋值符号左侧
右值示例:
在这个例子中,a + b 的结果是一个临时值,没有具体的身份(变量名),只能在赋值符号右侧使用,因此它是右值。
int a = 10;
int b = 20;
int c = a + b; // a + b 的结果是右值,因为它是一个临时值,没有具体的身份(变量名)
什么是左值引用什么是右值引用?
左值引用(lvalue reference)就是对一个左值进行引用的类型。 具体来说,它是一个具有名称的变量的别名,可以通过该别名访问和修改该变量的值。左值引用使用 T& 表示,其中 T 是被引用的变量的类型。
右值引用(rvalue reference)就是对一个右值进行引用的类型。 由于右值通常不具有名字,我们也只能通过引用的方式找到它的存在。右值引用使用 T&& 表示,其中 T 是被引用的变量的类型。
左值引用示例:
左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。 定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。
int main()
{// 以下的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& pvalue = *p;return 0;
}
右值引用示例:
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。 右值引用就是对右值的引用,给右值取别名。
int main()
{double x = 1.1, y = 2.2;// 以下几个都是常见的右值10;x + y;fmin(x, y);// 以下几个都是对右值的右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);// 这里编译会报错:error C2106: “=”: 左操作数必须为左值10 = 1;x + y = 1;fmin(x, y) = 1;return 0;
}
5.2左值引用与右值引用比较
左值引用总结:
(1)左值引用只能引用左值,不能引用右值。
(2)但是const左值引用既可引用左值,也可引用右值
int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a; // ra为a的别名//int& ra2 = 10; // 编译失败,因为10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;return 0;
}
右值引用总结:
(1)右值引用只能右值,不能引用左值。
(2)但是右值引用可以move以后的左值。
int main()
{// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 无法从“int”转换为“int &&”// message : 无法将左值绑定到右值引用int a = 10;int&& r2 = a;// 右值引用可以引用move以后的左值int&& r3 = std::move(a);return 0;
}
5.3右值引用使用场景和意义
左值引用的场景:
(1)做参数:
当函数需要传递大的对象或复杂的数据结构时,可以使用左值引用来做参数传递,以避免对象的复制。这样可以提高函数的执行效率,并减少内存占用。例如:
在这个例子中,ComplexObject 是一个复杂的数据结构,使用左值引用来做参数传递可以避免对象的复制。
void foo(const ComplexObject& obj) { // ...
}
(2)做返回值:
当函数需要返回一个大的对象或复杂的数据结构时,可以使用左值引用来做返回值,以避免对象的复制。这样可以提高函数的执行效率,并减少内存占用。例如:
在这个例子中,bar 函数返回一个 ComplexObject 类型的左值引用,以避免对象的复制。由于返回的是一个引用,调用者可以直接访问原始对象,而不是一个复制的副本。
ComplexObject& bar() { static ComplexObject obj; return obj;
}
综上,无论是做参数还是做返回值,它们都可以减少拷贝,提高效率。
以String的实现为例, 左值引用被用于实现字符串类的拷贝构造函数和赋值重载运算符。
在拷贝构造函数中,左值引用被用来接收一个传入的字符串对象(const string& s),这样可以避免对象的复制。通过创建一个临时对象(string tmp(s._str)),然后使用 swap 函数将临时对象的资源交换到当前对象,实现了深拷贝的效果。这里的左值引用作为参数传递方式,使得我们可以直接访问传入的字符串对象的成员变量。
在赋值重载运算符中,左值引用同样被用来接收一个传入的字符串对象(const string& s)。这里的左值引用的作用是使得我们可以将返回的对象赋值给当前对象。通过创建一个临时对象(string tmp(s)),然后使用 swap 函数将临时对象的资源交换到当前对象,实现了深拷贝的效果。最后,返回当前对象的引用(return *this),使得赋值操作可以连续进行。
综上,在这个代码片段中,左值引用被用于实现深拷贝的拷贝构造函数和赋值重载运算符,它使得我们可以直接访问传入的对象,避免对象的复制,提高了程序的性能。
// 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)
{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;
}
左值引用的短板:
但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。
下面是一个代码示例,演示了左值引用的短板:
class String {
public: String(const char* str = "") : _str(nullptr) { std::cout << "String(const char* str) -- 深拷贝" << std::endl; _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& other) : _str(nullptr) { std::cout << "String(const String& other) -- 深拷贝" << std::endl; _str = new char[strlen(other._str) + 1]; strcpy(_str, other._str); } String& operator=(const String& other) { std::cout << "String& operator=(const String& other) -- 深拷贝" << std::endl; if (this != &other) { delete[] _str; _str = new char[strlen(other._str) + 1]; strcpy(_str, other._str); } return *this; } ~String() { delete[] _str; } private: char* _str;
}; void printString(const String& str)
{ std::cout << "printString(const String& str)" << std::endl; std::cout << str._str << std::endl;
} int main()
{ String s1("Hello"); String s2 = "World"; printString(s1 + s2); // 这里会创建一个临时对象,无法用左值引用捕获 return 0;
}
在上面的代码中,我们定义了一个简单的 String 类,并实现了拷贝构造函数、赋值重载运算符和析构函数。在 main 函数中,我们创建了两个 String 对象 s1 和 s2,然后调用 printString 函数打印它们的拼接结果。
然而,在 printString 函数中,我们尝试通过左值引用来捕获传入的字符串对象,但是这里的传入参数实际上是一个临时对象(由 s1 + s2 创建),无法用左值引用捕获。这就是左值引用的短板之一,它无法绑定到临时对象或右值上,导致我们无法直接访问这些对象的资源。为了解决这个问题,C++11引入了右值引用的概念。
右值引用和移动语义解决上述问题:
使用右值引用和移动语义可以解决上述问题。具体做法是在 String 类中实现移动构造函数和移动赋值运算符,利用右值引用来捕获临时对象,并将其资源移动到当前对象中,避免深拷贝。
下面是修改后的代码示例:
我们在 String 类中实现了移动构造函数和移动赋值运算符,使用右值引用来捕获临时对象,并将其资源移动到当前对象中。在 main 函数中,临时对象就可以使用右值引用捕获,以便调用移动构造函数和移动赋值运算符。这样就可以避免深拷贝,提高程序的性能。
class String {
public: String(const char* str = "") : _str(nullptr) { std::cout << "String(const char* str) -- 深拷贝" << std::endl; _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& other) : _str(nullptr) { std::cout << "String(const String& other) -- 深拷贝" << std::endl; _str = new char[strlen(other._str) + 1]; strcpy(_str, other._str); } String(String&& other) : _str(nullptr) { std::cout << "String(String&& other) -- 移动构造" << std::endl; _str = other._str; other._str = nullptr; } String& operator=(const String& other) { std::cout << "String& operator=(const String& other) -- 深拷贝" << std::endl; if (this != &other) { delete[] _str; _str = new char[strlen(other._str) + 1]; strcpy(_str, other._str); } return *this; } String& operator=(String&& other) { std::cout << "String& operator=(String&& other) -- 移动赋值" << std::endl; if (this != &other) { delete[] _str; _str = other._str; other._str = nullptr; } return *this; } ~String() { delete[] _str; } private: char* _str;
}; void printString(const String& str)
{ std::cout << "printString(const String& str)" << std::endl; std::cout << str._str << std::endl;
} int main()
{ String s1("Hello"); String s2 = "World"; printString(s1 + s2); // 临时对象可以使用右值引用捕获 return 0;
}
5.4右值引用引用左值及其一些更深入的使用场景分析
按照语法,右值引用只能引用右值,但右值引用一定不能引用左值吗?
但是有些场景下,可能真的需要用右值去引用左值实现移动语义。当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。 C++11中,std::move()函数位于 头文件中,该函数可以将一个左值强制转化为右值引用,然后实现移动语义。
template<class _Ty>
inline typename remove_reference<_Ty>::type&& move(_Ty&& _Arg) _NOEXCEPT
{// forward _Arg as movablereturn ((typename remove_reference<_Ty>::type&&)_Arg);
}int main()
{bit::string s1("hello world");// 这里s1是左值,调用的是拷贝构造bit::string s2(s1);// 这里我们把s1 move处理以后, 会被当成右值,调用移动构造// 但是这里要注意,一般是不要这样用的,因为我们会发现s1的// 资源被转移给了s3,s1被置空了。bit::string s3(std::move(s1));return 0;
}
move函数使用示例:
void push_back (value_type&& val);
int main()
{list<bit::string> lt;bit::string s1("1111");// 这里调用的是拷贝构造lt.push_back(s1);// 下面调用都是移动构造lt.push_back("2222");lt.push_back(std::move(s1));return 0;
}// string(const string& s) -- 深拷贝
// string(string&& s) -- 移动语义
// string(string&& s) -- 移动语义
5.5完美转发
完美转发(Perfect Forwarding)是C++11引入的一种特性,它允许函数模板按照参数原来的形式(类型、值类别)将参数转发给其他函数,从而实现更灵活的编程。
完美转发的核心在于使用 std::forward 函数模板,它可以将左值转换为左值引用,将右值转换为右值引用,从而实现参数的完美转发。下面是一个简单的示例:
template<typename F, typename T1, typename T2>
void flip(F f, T1&& t1, T2&& t2)
{ f(std::forward<T2>(t2), std::forward<T1>(t1));
}
在这个示例中,flip 函数模板接受一个函数对象 f 和两个参数 t1 和 t2,并将它们转发给函数对象 f,但是转发的顺序与原始顺序相反。通过使用 std::forward,我们可以保证参数的类型和值类别得到正确的保留和转发。
完美转发在很多情况下都非常有用,比如在实现代理函数、工厂函数、回调函数等场景中,它可以让我们更灵活地处理参数,并避免不必要的拷贝或移动操作。
完美转发在传参的过程中保留对象原生类型属性:
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; }// std::forward<T>(t)在传参的过程中保持了t的原生类型属性。
template<typename T>
void PerfectForward(T&& t)
{Fun(std::forward<T>(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;
}
完美转发的示例:
void print(int&& i) { std::cout << "rvalue: " << i << std::endl;
} void print(const int& i) { std::cout << "lvalue: " << i << std::endl;
} template<typename T>
void forwardPrint(T&& t) { print(std::forward<T>(t));
} int main() { int i = 42; forwardPrint(i); // lvalue: 42 forwardPrint(std::move(i)); // rvalue: 42 return 0;
}
6.新的类功能
默认成员函数:
原来C++类中,有6个默认成员函数:
(1)构造函数 (2)析构函数
(3)拷贝构造函数 (4)拷贝赋值重载
(5)取地址重载 (6)const 取地址重载
C++11 新增了两个:移动构造函数和移动赋值运算符重载。
针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:
(1)如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。 默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
(2)如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。 默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)
(3)如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。
强制生成默认函数的关键字default:
C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用default关键字显示指定移动构造生成。
class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p):_name(p._name),_age(p._age){}Person(Person&& p) = default;private:bit::string _name;int _age;
};int main()
{Person s1;Person s2 = s1;Person s3 = std::move(s1);return 0;
}
禁止生成默认函数的关键字delete:
如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。
class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p) = delete;private:bit::string _name;int _age;
};int main()
{Person s1;Person s2 = s1;Person s3 = std::move(s1);return 0;
}
相关文章:
【C++】C++11——右值引用和移动语义、左值引用和右值引用、右值引用使用场景和意义、完美转发、新的类功能
文章目录 C115.右值引用和移动语义5.1左值引用和右值引用5.2左值引用与右值引用比较5.3右值引用使用场景和意义5.4右值引用引用左值及其一些更深入的使用场景分析5.5完美转发 6.新的类功能 C11 5.右值引用和移动语义 右值引用是C11引入的一个新特性,用于支持移动语义…...
Spring Boot的创建和使用(JavaEE进阶系列2)
目录 前言: 1.什么是Spring Boot?为什么要学习Spring Boot? 2.Spring Boot优点 3.创建Spring Boot项目 3.1准备工作 3.2Spring Boot创建 3.2.1通过idea的方式创建 3.2.2通过网页创建 4.Spring Boot中的配置文件 4.1Spring Boot配置…...
【OLSR路由协议】链路状态路由(OLSR)协议中选择多点中继节点算法研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
双重差分模型(DID)论文写作指南与操作手册
手册链接:双重差分模型(DID)论文写作指南与操作手册https://www.cctalk.com/m/group/90983583?xh_fshareuid60953990 简介: 当前,对于准应届生们来说,毕设季叠加就业季,写作时间显得十分宝贵…...
ping 的工作原理
ping 是一个常用于网络诊断的命令行工具,用于测试两台计算机之间的网络连通性。它的工作原理如下: 发出 ICMP Echo 请求: 当你在终端中运行 ping 命令并指定目标主机的IP地址或域名时,计算机会创建一个特殊的ICMP(In…...
93. 复原 IP 地址
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 . 分隔。 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.24…...
竞赛选题 机器视觉的试卷批改系统 - opencv python 视觉识别
文章目录 0 简介1 项目背景2 项目目的3 系统设计3.1 目标对象3.2 系统架构3.3 软件设计方案 4 图像预处理4.1 灰度二值化4.2 形态学处理4.3 算式提取4.4 倾斜校正4.5 字符分割 5 字符识别5.1 支持向量机原理5.2 基于SVM的字符识别5.3 SVM算法实现 6 算法测试7 系统实现8 最后 0…...
第15届蓝桥STEMA测评真题剖析-2023年8月20日Scratch编程中级组
[导读]:超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成,后续会不定期解读蓝桥杯真题,这是Scratch蓝桥杯真题解析第155讲。 第15届蓝桥第1次STEMA测评,这是2023年8月20日举办的STEMA,比赛仍然采取线上形式。这…...
html5 checkbox
1 选中状态的设置与获取 (1)获取checkbox是否选中: $("#checkbox").is(":checked");$("#checkbox-id")get(0).checked$(#checkbox-id).attr(checked)(2)设置checkbox是否选中 $("…...
安装matplotlib_
安装pip 安装matplotlib 安装完毕 导入出现bug.........
STM32复习笔记(六):STM32远程升级BootLoader相关
目录 Preface: (一)STM32上电启动流程 (二)BootLoader相关 (三)Clion配置 Preface: 有关STM32的BootLoader主要还是参考了许多大佬的文章,这里只是简单地列举一下&am…...
MASA MAUI iOS 文件下载与断点续传
文章目录 背景介绍方案及代码1、新建MAUI项目2、建立NSUrlSession会话连接3、使用NSUrlSessionDownloadTask 创建下载任务4、DidWriteData 监听下载5、DidFinishDownloading 完成下载6、CancelDownload (取消/暂停)下载7、ResumeDownload 恢复下载8、杀死进程-恢复下载 效果图总…...
NPDP产品经理知识(产品创新流程)
1.复习组合管理: 组合管理的目标 > 价值最大化,项目平衡,战略一致,管道平衡(资源需求和供给),盈利充分 (实现财务目标) 产品创新流程就是管理风险的过程。 模糊前端: 产品创新章程:PIC 包…...
Android日常——记一次Android事件分发需求的实现
背景:在一个事件分发复杂的view中,插入一个可点击的控件,且不能影响到本身的事件分发。 尝试: 1.对view本身设置点击事件;由于view整体是交由root view去处理分发,存在滑动、边界处理、调出其他界面等复杂操作。设置点…...
【Python】函数(function)和方法(method)的区别
这里先说结论,为了满足心急的小伙伴:method与function的最大区别就是参数有无进行绑定。 自定义类Test: 首先先来一个自定义类: class Test:def Func_normal(arg):print(Func_normal:,arg)staticmethoddef Func_static(arg):pri…...
linux入门---信号的理解
目录标题 如何理解计算机中的信号如何查看计算机中的信号初步了解信号的保存和发送如何向目标进程发送信号情景一:使用键盘发送信号情景二:系统调用发送信号情景三:硬件异常产生信号情景四:软件条件产生信号 核心转储信号的两个问…...
nn.Linear(d, num_units, bias=True)设置bias和不设置bias有什么区别?
nn.Linear(d, num_units, biasTrue)是PyTorch中定义的一个全连接线性层。其中,d是输入特征的数量,num_units是输出特征的数量,而bias参数决定是否在这个线性变换中添加一个偏置项。 设置biasTrue与biasFalse的区别如下: 数学表示…...
代码随想录 Day10 栈与队列 LeetCode T239 滑动窗口的最大值 T347 前K个高频元素
简要介绍一下单调队列和优先级队列的不同 元素顺序的处理:单调队列中,元素的顺序是单调的,也就是说,队列中的元素按照特定的单调性(递增或递减)排列。这种特性使得单调队列在处理一些问题时非常高效&#…...
vue/自定义指令
需求: 页面有个input元素,现在要鼠标光标聚焦在上面,让每个页面上的标签都可以聚焦光标,比如,从A页面跳转到B页面的时候,我们依然要聚焦。如果要一遍遍地操作dom就会很麻烦。 这个时候,为了方便…...
借用binlog2sql工具轻松解析MySQL的binlog文件,再现Oracle的闪回功能
借用binlog2sql工具轻松解析MySQL的binlog文件 简介依赖配置用户权限选项配置案例:误UPDATE表数据回滚binlog2sql VS mysqlbinlog 看腻文章了就来听听视频演示吧:https://www.bilibili.com/video/BV1Zj411k7VW/ 简介 binlog2sql是美团大众点评开源的一…...
一次解决Pytorch训练时损失和参数出现Nan或者inf的经历
目前在做实验,参考了一个新的网络架构之后发现训练时损失出现Nan,参数了出现了inf的情况,先说说我的排查经历。 首先肯定是打印损失,损失是最容易出现Nan的,有各种原因,网上也有很多解决办法,我…...
【python入门篇】列表简介及操作(2)
列表是什么? 列表是由一系列按特定顺序排列的元素组成。你可以创建包含字母表中的所有字母、数字 0~9 或所有家庭成员的列表;也可以将任何东西加入列表中,其中的元素之间可以没有任何关系。列表通常包含多个元素,因此给列表指定一…...
数据结构与算法——19.红黑树
这篇文章我们来讲一下红黑树。 目录 1.概述 1.1红黑树的性质 2.红黑树的实现 3.总结 1.概述 首先,我们来大致了解一下什么是红黑树 红黑树是一种自平衡的二叉查找树,是一种高效的查找树。红黑树具有良好的效率,它可在 O(logN) 时间内完…...
js题解(三)
文章目录 柯里化模块乘法改变上下文 柯里化 已知 fn 为一个预定义函数,实现函数 curryIt,调用之后满足如下条件: 1、返回一个函数 a,a 的 length 属性值为 1(即显式声明 a 接收一个参数) 2、调用 a 之后&a…...
CompletableFuture异步回调
CompletableFuture异步回调 CompletableFutureFuture模式CompletableFuture详解1.CompletableFuture的UML类关系2.CompletionStage接口3.使用runAsync和supplyAcync创建子任务4.设置子任务回调钩子5.调用handle()方法统一处理异常和结果6.线程池的使用 异步任务的串行执行thenA…...
Python中匹配模糊的字符串
嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 如何使用thefuzz 库,它允许我们在python中进行模糊字符串匹配。 此外,我们将学习如何使用process 模块,该模块允许我们在模糊…...
PHP图片文件管理功能系统源码
文件图库管理单PHP源码直接解压就能用,单文件,indexm.php文件可以重新命名,上传到需要访问的目录中, 可以查看目录以及各个文件,图片等和下载及修改管理服务。 源码下载:https://download.csdn.net/downloa…...
(枚举 + 树上倍增)Codeforces Round 900 (Div. 3) G
Problem - G - Codeforces 题意: 思路: 首先,目标值和结点权值是直接联系的,最值不可能直接贪心,一定是考虑去枚举一些东西,依靠这种枚举可以遍历所有的有效情况,思考的方向一定是枚举 如果去…...
websocket逆向【python实现websocket拦截】
python实现websocket拦截 前言一、拦截的优缺点优点:缺点:二、实现方法1.环境配置2.代码三、总结前言 开发者工具F12,筛选ws后,websocket的消息是这样显示的,如何获取这里面的消息呢? 以下是本篇文章正文内容 一、拦截的优缺点 主要讲解一下websocket拦截的实现,现在…...
软件测试自动化的成本效益分析
随着软件测试技术的发展,人们已经从最初的手工测试转变为手工和自动化技术相结合的测试方法。目前,人们更多的是关心自动化测试框架、自动化测试工具以及脚本研究等技术方面,而在软件自动化测试方案的效益分析方面涉及较少。 软件测试的目的是…...
优化志愿网站/网络精准推广
作为网页设计师或前端工程师,你可能还记得曾经的那个网页大小建议:一个网页(包括HTML、CSS、Javacript、Flash和图片)尽量不要超过30KB的大小,随着互联网的日益庞大,网络带宽也在飞速发展,很多设计师已经不再考虑这条3…...
迈创网站建设/友链交换
大家好,我是时间财富网智能客服时间君,上述问题将由我为大家进行解答。以照片为例,16:9尺寸的照片是指长边与短边之比是16:9,与照片像素的多与少没有关系,例如可以是长边是160像素、短边是90像素…...
百度wordpress插件下载地址/佛山外贸seo
最近,有关最新版本的南大核心目录的帖子应该又又又刷屏了。有关北大核心和南大核心目录的帖子,好像已经成了惯例,隔三差五就会被拿出来晾凉晒晒,收割一波阅读量。学术圈的人,对于核心期刊的关注,可能甚于关…...
wordpress 做网站/网推公司干什么的
2016年6月6日, 加州讯,世界领先的高性能计算、数据中心端到端互连方案提供商Mellanox(纳斯达克交易所代码: MLNX)今天宣布,正式推出针对网络及存储应用的BlueField 系列SoC可编程芯片。该系列产品能够满足业界日益增长…...
wordpress侧栏文本代码/网络推广公司简介
c表a表查询语句 select a.*,c.* FROM a LEFT JOIN c on FIND_IN_SET(a.a_id,c.a_id)...
网站开发协助方案/大连网站建设费用
引入引入jqueVirevol ai is a collaborative visual shopping app. We run a remote-first lean team, have been for 2 years. To do our magic, we swim with a lot of data.Virevol ai是一款协作式视觉购物应用程序。 我们拥有一支偏远的精益团队,已有2年以上的经…...