R-value reference of new features in c++11

Posted by Michael001 on Fri, 14 Jan 2022 06:54:30 +0100

1. First, let's talk about what are left and right values

Lvalues are address variables that can be accessed; A variable whose right value does not take an address.

2. What is citation?

A reference is essentially an alias. You can modify the value of a variable through a reference. You can avoid copying when passing parameters.

3. What is an lvalue reference (lvalue variable is preceded by &)

A reference that can point to an lvalue but cannot point to an lvalue is an lvalue reference.

int a = 10;
int &b = a;
int &c = 10;//Error, lvalue reference points to lvalue

Of course, you can also point to the right value through const:

const int &c = 10;//Compile passed

Const 'lvalue reference will make it impossible to modify the pointing value, so it can point to the right value. This is one of the reasons why const & is used as a function parameter, such as the push of std::vector_ back:

void push_back(const value_type&val);

If there is no const. So VEC push_ Back (2) won't pass.

4. What is an R-value reference and what is the purpose of introducing an R-value reference? (variables are preceded by & &)

You can point to the right value, but you can't point to the left value is the right value reference.

int a = 10;
int &&b = 10;//correct
int &&c = a;//Incorrect, pointing to an lvalue

Can an R-value reference point to an l-value?

The answer is yes, through std::move();

int a = 10;
int &&b = 10;//correct
int &&c = std::move(a);//correct

The only function of move is to convert the left value to the right value.

We can get the comparison between lvalue reference and lvalue reference:

(1). In terms of performance, both left and right references are to avoid copying.

(2) An R-value reference can point to an R-value or an l-value. Lvalue references can only point to lvalues. (you can point to the right value through const).

(3) As a formal parameter, the right value is more flexible. Because an lvalue reference cannot be modified when it accepts an lvalue.

5. Application scenario of right value reference and std::move

(1) Implement mobile semantics:

Right value reference and std::move are widely used in STL and custom classes to realize semantic movement and avoid copying, so as to improve program performance.

example:

class Array {
 public: Array(int size) : size_(size) {
     data = new int[size_]; } 
    // Deep copy structure 
    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]; } 
    } 
    
    // Deep copy assignment 
    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_; 
};

In the above example, the copy constructor and assignment operator overload function have used lvalue references to avoid a copy, but

Deep copy is required internally, which cannot be avoided. Therefore, you can use right value references to implement mobile semantics.

class Array {
 public: Array(int size) : size_(size) {
     data = new int[size_]; } 
    // Deep copy structure 
    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]; } 
    } 
    
    // Deep copy assignment 
    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]; } 
    }
    
    
    //move
    Array( Array&& temp_array){
        data_ = temp_array.data_;
        size_ = temp_array.size()_;
        //To prevent temp_ When array destructs, delete data is set to null in advance
        temp_array.data_ = nullptr;
    }

     ~Array() {
         delete[] data_; 
    } 
public: 
    int *data_;
    int size_; 
};

(2) Instance: vector::push_back() uses std::move to improve performance

int main(){
    string str1 = "absgssag";
    vector<string> vec;
    vec.push_back(str1);//Traditional method, copy
    vec.push_back(static::move(str1));//Call the push of mobile semantics_ Back(), avoid copying, and str1 becomes an empty string
    vec.emplace_back(std::move(str1));Call mobile semantic emplace_back(),Avoid copying, str1 Become an empty string
    vec.emplace("absgssag");
}

//std::vector method definition
void push_back(const value_type&val);
void push_back(value_type&& val);

void emplace_back(Args&&... args);

To sum up, it is recommended to use std::move to trigger the mobile semantics in the scenario where the movable object needs to be copied and the copied object is no longer needed after being copied, so as to improve the performance.

Topics: C++