左值右值
左右值的概念
简单来讲,左值(lvalue: located value)就是可以拿到地址的值。右值就是不能拿到地址的值。
比如
int a = 10;
a是左值,10是右值。
int a = func();
a是左值,func()是右值。
右值引用符号: &&
int&& ra = 10; //ra是右值引用,但其本身是一个左值(因为可以拿到它的地址),10是右值
程序判断左右值:
判断类型是否是左右值:
c++自带的判断函数:
std::is_lvalue_reference<type> //左值引用
std::is_rvalue_reference<type> //右值引用
例子:
{
cout << "is lvalue: " << endl;
cout << "int:" << is_lvalue_reference<int>::value << ", ";
cout << "int&:" << is_lvalue_reference<int&>::value <<", ";
cout << "int&&:" << is_lvalue_reference<int&&>::value << ", ";
cout << "int*:" << is_lvalue_reference<int*>::value << ". ";
cout << "\n";
cout << "is rvalue: " << endl;
cout << "int:" << is_rvalue_reference<int>::value << ", ";
cout << "int&:" << is_rvalue_reference<int&>::value <<", ";
cout << "int&&:" << is_rvalue_reference<int&&>::value << ", ";
cout << "int*:" << is_rvalue_reference<int*>::value << ". ";
cout << "\n";
int&& ra = 10;
cout << "decltype(ra):" << is_rvalue_reference<decltype(ra)>::value << endl;
}
运行结果:
移动语义
C++std::move
函数。
定义:
template <class T>
typename remove_reference<T>::type&& move (T&& arg) noexcept;
作用:
返回一个arg的右值引用。
官方例子:
// move example
#include <utility> // std::move
#include <iostream> // std::cout
#include <vector> // std::vector
#include <string> // std::string
int main () {
std::string foo = "foo-string";
std::string bar = "bar-string";
std::vector<std::string> myvector;
myvector.push_back (foo); // copies
myvector.push_back (std::move(bar)); // moves
std::cout << "myvector contains:";
for (std::string& x:myvector) std::cout << ' ' << x;
std::cout << '\n';
cout << "foo: " << foo << endl;
cout << "bar: "<<bar << endl;
return 0;
}
第一次调用myvector.push_back复制了foo的值到vector(foo保持原来的值。第二次调用使用了move函数把bar的值移动到vector里面(bar失去了他的值)。
输出:
myvector contains: foo-string bar-string
foo: foo-string
bar:
移动构造函数
移动构造函数的输入是右值,编译器会自动调用移动构造函数来减少不必要的深度拷贝,比如下面的例子,因为CatBorn函数里的cat即将析构,是一个右值,所以编译器调用移动构造函数,把cat的pweight资源拿过来用。
class Cat
{
public:
Cat(int w = 1): pweight(new int(w)){
cout << "cat normal constructor." <<endl;
}
Cat(const Cat& cat) : pweight(new int(*(cat.pweight))){
//拷贝构造函数
cout << "cat copy constructor." << endl;
}
Cat(Cat&& cat): pweight(cat.pweight){
//移动构造函数
cat.pweight = nullptr;
cout << "cat move constructor" << endl;
}
void Cry(){
cout << "cat cry: " << *pweight;
}
private:
int* pweight;
};
Cat CatBorn()
{
Cat cat;
return cat;
}
int main()
{
CatBorn().Cry();
}
运行输出:
cat normal constructor.
cat move constructor
cat cry: 1