1.首先说一下什么是左值和右值
左值就是可以取地址 变量;右值不可取地址的变量。
2.什么是引用?
引用本质是别名,通过引用可以修改变量的值。传递参数时可以避免拷贝。
3.什么是左值引用(左值变量前面取&)
能指向左值,不能指向右值的引用就是左值引用。
int a = 10;
int &b = a;
int &c = 10;//错误,左值引用指向了右值
当然也是可以通过const来指向右值:
const int &c = 10;//编译通过
const'左值引用会使得不能修改指向值,因此可以指向右值。这也是为什么要使用const&作为函数参数的原因之一了,例如:std::vector的push_back:
void push_back(const value_type&val);
如果没有const。那么vec.push_back(2)就不会通过了。
4.什么是右值引用,右值引用引入的目的是什么?(变量前面取&&)
可以指向右值,不能指向左值的就是右值引用。
int a = 10;
int &&b = 10;//正确
int &&c = a;//不正确,指向了左值
右值引用可以指向左值吗?
回答是肯定的,通过std::move();
int a = 10;
int &&b = 10;//正确
int &&c = std::move(a);//正确
move的唯一的作用就是将左值转换成了右值。
我们可以得到,左值引用和右值引用对比:
(1).从性能上来说,左右引用都是为了避免拷贝。
(2)右值引用可以指向右值,也可以指向左值。而左值引用只能指向左值。(通过const可以指向右值)。
(3)作为形式参数的时候,右值更加的灵活。因为左值引用接受右值时无法进行修改。
5.右值引用和std::move的应用场景
(1)实现移动语义:
右值引用和std::move被广泛的应用于STL和自定义的类中实现语义移动,避免拷贝,从而提高程序性能。
例子:
class Array {
public: Array(int size) : size_(size) {
data = new int[size_]; }
// 深拷贝构造
Array(const Array& temp_array) {
size_ = temp_array.size_;
data_ = new int[size_];
for (int i = 0; i < size_; i ++) { data_[i] = temp_array.data_[i]; }
}
// 深拷贝赋值
Array& operator=(const Array& temp_array) {
delete[] data_; size_ = temp_array.size_;
data_ = new int[size_];
for (int i = 0; i < size_; i ++) { data_[i] = temp_array.data_[i]; }
}
~Array() {
delete[] data_;
}
public:
int *data_;
int size_;
};
在上面的例子中,拷贝构造函数和赋值运算符重载函数已经使用左值引用避免了一次拷贝,但是
内部需要实现深拷贝,无法避免。因此可以使用右值引用来实现移动语义。
class Array {
public: Array(int size) : size_(size) {
data = new int[size_]; }
// 深拷贝构造
Array(const Array& temp_array) {
size_ = temp_array.size_;
data_ = new int[size_];
for (int i = 0; i < size_; i ++) { data_[i] = temp_array.data_[i]; }
}
// 深拷贝赋值
Array& operator=(const Array& temp_array) {
delete[] data_; size_ = temp_array.size_;
data_ = new int[size_];
for (int i = 0; i < size_; i ++) { data_[i] = temp_array.data_[i]; }
}
//移动
Array( Array&& temp_array){
data_ = temp_array.data_;
size_ = temp_array.size()_;
//为了防止temp_array析构的时候delete data,提前置空
temp_array.data_ = nullptr;
}
~Array() {
delete[] data_;
}
public:
int *data_;
int size_;
};
(2)实例:vector::push_back()使用std::move提高性能
int main(){
string str1 = "absgssag";
vector vec;
vec.push_back(str1);//传统方法,copy
vec.push_back(static::move(str1));//调用移动语义的push_back(),避免拷贝,str1变成空串
vec.emplace_back(std::move(str1));调用移动语义的emplace_back(),避免拷贝,str1变成空串
vec.emplace("absgssag");
}
//std::vector方法定义
void push_back(const value_type&val);
void push_back(value_type&& val);
void emplace_back(Args&&... args);
综上所述,可移动对象在<需要拷贝且被拷贝者之后不再被需要>的场景,建议使用std::move触发移动语义,提升性能。