目录
4.移动构造和移动赋值的默认生成条件(重载赋值的右值引用和移动构造跟拷贝构造差不多)
1.右值和左值
左值与右值是C语言中的概念,但C标准并没有给出严格的区分方式,一般认为:可以放在=左边的,或者能 够取地址的称为左值,只能放在=右边的,或者不能取地址的称为右值,但是也不一定完全正确。
左值:可以取地址,可以赋值的
- 下面的a,r1,p,r2就属于左值
- b,r3虽然是被const修饰不能赋值,但是也是左值,左值是能取地址的值,可以被const修饰也是左值
int a = 10; int& r1 = a; int* p = &a; int& r2 = *p; const int b = 10; const int& r3 = b;
右值:不能取地址的值
- 纯右值,比如:X+Y, 10。
- 将亡值,比如:表达式的中间结果((X+(Y+Z))Y+Z的值)、函数按照值的方式进行返回(返回值)。
//常见的右值 10; x + y; min(x, y);
2.左值引用和右值引用
- 左值引用:b,d
- 右值引用:a1,b1,c1
左值引用使用:&,右值引用使用:&&;同时它们也是可以交叉引用
//左值引用左值 int a=1; int& b=a; int* c=&a; int& d=*c; int X=10,int Y=20; //右值引用右值 int&& a1=10; int&& b1=X+Y; int&& c1=min(X,Y);
2.1左右值的交叉引用
-
左值引用右值-- 不能直接引用,但是const 左值引用可以引用右值
-
右值引用左值-- 不能直接引用,但是可以右值引用可以引用move以后左值
//左值引用右值-- 不能直接引用,但是const 左值引用可以引用右值 const int& a=2; //右值引用左值-- 不能直接引用,但是可以右值引用可以引用move以后左值 int a1=1000000; int&& b1=move(a1)
2.2左值引用右值的具体情景
- 当参数直接传常数(右值),那么引用必须加一个const
3.移动构造
class string
{
public:
// 拷贝构造
string(const string& s)
:_str(new char[strlen(s._str) + 1])
, _size(s._size)
, _capacity(s.s_capacity)
{
cout << "string(const string& s) -- 深拷贝" << endl;
strcpy(_str, s._str);
}
// 移动构造
string(string&& s)
:_str(nullptr)
, _size(s._size)
, _capacity(s._capacity)
{
cout << "string(string&& s) -- 资源转移" << endl;
_str = s._str;
s._str = nullptr;
}
string operator+(char ch)
{
string tmp(*this);
push_back(ch);
return tmp;
}
private:
char* _str;
size_t _size;
size_t _capacity; // 不包含最后做标识的\0
};
3.1移动构造:资源转移,没有了深拷贝和delete效率大大提高
- 没有深拷贝了,析构也减少了,效率提升;
- 将亡值资源被转移了,它被换成nullptr,调析构函数,没有资源需要析构效率提高
3.5push_back的右值引用的重载
- 所有容器调用push_back都有左值引用和右值引用版本
4.移动构造和移动赋值的默认生成条件(重载赋值的右值引用和移动构造跟拷贝构造差不多)
- 移动构造和移动赋值默认生成条件:当它本身被实现,且析构函数、拷贝构造、赋值运算符重载都没有实现才会默认生成;
5.万能引用 (模板参数引用&&)
- 万能引用就是模板参数引用,使用的符号和右值引用相同:&&
- 可以接受左值也可以接受右值
- 接受后使用退化成了左值
void Fun(int& x) { cout << "左值" << endl; }
void Fun(int&& x) { cout << "右值" << endl; }
void Fun(const int& x) { cout << "const 左值" << endl; }
void Fun(const int&& x) { cout << "const 右值" << endl; }
template<class T>
void PerfectForward(T&& t)
{
Fun(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;
}
5.1完美转发
完美转发是目标函数总希望将参数按照传递给转发函数(forward)的实际类型转给目标函数,而不产生额外的开销;如果相应实参是左值,它就应该被转发为左值;如果相 应实参是右值,它就应该被转发为右值
格式:forward<模板参数>(实参)
使用完美转发结果: