1 移动语义
移动语义是 C++11 引入的一种新特性,移动的意思是转移所有权,它允许资源的所有权从一个对象转移到另一个对象,而不需要进行昂贵的拷贝操作。
2右值引用
左值 :表达式结束后依然存在的持久对象,可取地址。
右值 :表达式结束后就不再存在的临时对象,不可取地址。
int x1 = 1; \\1是右值,x1是左值
为支持移动语义,C++11引入了一种新的引用类型,称为"右值引用",使用"&&"来声明。而使用"&"声明的引用,则称为"左值引用"。
右值引用只能够引用没有名称的临时对象以及使用std::move标记的对象。由于右值都是临时的值,临时值释放后也就不再持有属性的所有权,因此右值引用相当于转移资源所有权的行为。
#include<iostream>
int main() {
int&& rRef1 = 13;
std::cout << rRef1 << std::endl;
int val = 8 ;
//int&& rRef2 = val; //不能引用左值
int&& rRef2 = std::move(val) ; //使用std::move将左值所有权转移到右值,但并不改变原变量的所有权
std::cout << rRef2 << std::endl;
std::cout << val << std::endl;
return 0;
}
3 lambda表达式做右值
lambda表达式可以创建一个匿名函数对象,是右值,可以作为参数传递给其他函数
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
//用通用函数模板表示lambda表达式类型
template<typename F>
void func1(std::vector<int>& vec, F && fun) {
std::for_each(vec.begin(), vec.end(), fun);
}
//用函数对象(包含确定的函数返回值类型和参数类型)表示lambda表达式类型
using FType = std::function<void(int&)>;
void func2(std::vector<int>& vec, FType&& fun) {
std::for_each(vec.begin(), vec.end(), fun);
}
int main() {
std::vector<int> numbers1 = { 1, 2, 3, 4, 5 }, numbers2 = { 1, 2, 3, 4, 5 };
//使用lambda表达式创建一个右值函数对象,它将每个元素乘以2
func1(numbers1, [](int &x) {
x = x * 2;
});
func2(numbers2, [](int& x) {
x = x * 2;
});
//输出修改后的numbers1,numbers2
for (int n : numbers1) {
std::cout << n << " ";
}
std::cout<<std::endl;
for (int n : numbers2) {
std::cout << n << " ";
}
return 0;
}
4 移动构造函数
移动构造函数是一种特殊的构造函数,它用于创建一个新对象,并将一个已存在的对象的所有资源转移到新对象上。移动构造函数通常用于优化性能,因为它可以避免不必要的复制操作。
#include <iostream>
using namespace std;
class Resource {
public:
Resource() : data(new int(7)) {
cout << "Resource acquired." << endl;
}
~Resource() {
delete data;
cout << "Resource released." << endl;
}
//移动构造函数
Resource(Resource&& other): data(other.data) {
other.data = nullptr; //此时data和other.data指向相同的数据,调用析构函数进行delete时会造成麻烦,故应将原来的指针other.data设置为空指针
cout << "Resource moved." << endl;
}
//禁用拷贝构造函数
Resource(const Resource&) = delete; //禁止Resource r1(r2);
Resource& operator=(const Resource&) = delete; //禁止Resource r1 = r2;
void ShowResource()
{
cout << *data << endl;
}
private:
int* data;
};
int main() {
Resource r1;
Resource r2(std::move(r1)); //调用移动构造函数
r2.ShowResource();
Resource r3 = Resource(); //虽然Resource()是右值,但仍调用普通构造函数,因为编译器优化了构造过程
return 0;
}