左值及右值
int a = 10;
等号左边的为左值,可以取地址;等号右边的为右值,不可以取地址,没有地址的字面值或临时值一般右值。
左值引用和右值引用
int a = 10;
int &b = a; // 左值引用
int && c = 10; .// 右值引用
int &&ref_right = a;//编译不通过,右值引用不可以指向左值
const的左值引用可以指向右值,因为const的左值引用不会修改指向值,因此可以指向右值,所以常使用**const &**作为函数参数。
const int &ref = 5;
右值引用也可以使用std::move指向左值。
int a = 5;
int &&ref = move(a);
此处打印a的值仍是5,并不是空值。实际上使用move实现的static_cast<T&&>(lvalue)功能,将左值转成右值引用。单纯的使用move(x)不会有性能提升。此外,右值引用的变量名称是左值。
int a = 5;
int &&ref = move(a);
ref = 6;
cout << "a:" << a << ",ref:" << ref << endl;
输出:a:6,ref:6
函数传参时,从性能上来讲,左值引用和右值引用没有区别,传参时都可以避免拷贝。但右值引用更灵活,虽然const左值引用也可以做到左右值都接受,但它无法修改,有一定局限性。
右值引用和std::move如何提高性能
C++传值默认是copy,copy开销比较大;C++11引入右值引用(&&), 在使用Move操作,可以避免copy拷贝,从而提升程序性能。
在类的拷贝构造函数和拷贝赋值函数中,虽然使用了左值引用来减少一次拷贝,但是深拷贝仍然需要拷贝,对程序性能仍然有影响。如果存在只需要将原始数据移动过来,原始数据可以删除的场景,可以用右值引用来实现移动语义,避免深拷贝来提高性能。但move本身只做类型转换,对性能无影响。
移动构造和移动赋值操作
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,提前置空其data_
temp_array.data_ = nullptr;
}
~Array() {
delete[] data_;
}
public:
int *data_;
int size_;
};
vector中的push_back和emplace_back函数,参数为左值意味着深拷贝,参数为右值意味着移动。