Specific use of R-value reference of C + + 11

Time:2021-12-2

C + + 11 introduces STD:: move semantics, right value reference, mobile construction and perfect forwarding. As this part is relatively long, it is divided into three articles.

Before we look at these features, let’s introduce some problems.

1、 Problem import

  1. When the return value of a function is passed, how many object constructions and copies occur?
  2. How many times does an object construct occur when the formal parameter of a function is a value transfer?

Let’s look at a piece of code first,


// main.cpp
#include <iostream>
using namespace std;

class A{
public:
  A(){
   cout<<"class A construct!"<<endl;
  } 
  A(const A&){
   cout<<"class A copy!"<<endl;
  }
  A& operator=(const A&){
   cout<<"assignment called!"<<endl;
  }
  ~A(){
   cout<<"class A destruct!"<<endl;
  }
};

A get_A_value(){
  return A();
}
int main(){
  A a = get_A_value();
  return 0;
}

Compile with G + +; Note the use of – fno elide constructors to turn off omitted construction optimizations


g++ main.cpp -fno-elide-constructors

You can get the following output

class A construct!
class A destruct!
class A copy!
class A destruct!
class A destruct!

You can see a = get_ A_ value(); One line of code actually produces 1 object construction and 2 object copy construction! Specifically

  • In get_ A_ In value (), a () constructs a temporary object, and a construction occurs;
  • When the function returns, the temporary object will be copied as the return value, and a copy will occur;
  • A = copy construction occurred for the return value of the function.

If compiler optimization is used (default), the copy of the temporary object and the copy of the final object constructed with the return value will be omitted; That is, there is only one copy and destruction.

class A construct!
class A destruct!

If you change the above code


// ... A

void pass_A_by_value(A a){

}
int main(){
  A a;
  pass_A_by_value(a);
  return 0;
}

When removing the optimized G + + main.cpp – fno elide constructors, the output is

class A construct!
class A copy!
class A destruct!
class A destruct!

1 construction plus 1 copy.

Therefore, if someone asks this question during the next interview, you can say: by default, the copy of temporary objects will be omitted after compiler optimization. If – fno elide constructors is used to omit optimization, the copy of temporary objects will also be considered.

In fact, without optimization, the copy constructor will be called when:

  1. When a local object in a function is returned as a return value (not a reference), it will be copied (returned as a temporary object)
  2. Copy construction occurs when the function parameter is passed value
  3. When an object is initialized with another object

The frequent construction of objects is the overhead of the program, especially when there is memory on the heap (such as new members) inside the object, new needs to be used to apply for a piece of memory every time the construction is copied, resulting in performance degradation. For case 2, it is a good habit to pass a reference as a parameter if the function parameter is read-only (that is, it will not be modified in the program), that is, pass_ A_ by_ refrence(const A &a); For case 1, the compiler will optimize for us; For case 3, C + + 11 introduces the concept of a mobile constructor, which will get * * R-value reference *, and move the “resource” of the R-value to the new object. In this process, no new memory will be applied, so as to improve efficiency and performance.

Therefore, to understand the keywords “mobile construction” and “mobile semantics”, we must first understand the right value and right value reference.

2、 Right value and right value reference

2.1 lvalue and rvalue

I. in problem import, we mentioned temporary objects, that is, objects that only exist “temporarily” when the function returns a value (if it runs beyond that line, its lifetime will end). This temporary return value is an R-value;
The most intuitive definition of the right value is, as the name suggests:

The value on the right of assignment operator = is the right value; On the left is an lvalue

as

A a = foo(); //  Foo () is the right value
char *x = "thu"; //  "Thu" is both literal and right value
a = b + c; //  B + C is also an R-value

In C + +, another definition is:

Lvalue can obtain address and name; Can not get the address, no name for the right value.

Therefore, a = foo() can use & A to obtain the address of a, a is an lvalue, but it cannot obtain the address of foo(), (& foo()) cannot be compiled, and the temporary object returned by foo() also has no name, so it is an lvalue.

In C + + 11, there are two kinds of right values, one is xvalue (expiring value) and the other is pure right value (prvalue, pure rvalue) [1]. The temporary object returned by the function without reference, the result of the operation expression, literals such as 1, 3.14 and ‘C’ all belong to pure right values. Xvalue is introduced by C + + 11, such as the return value of a & & function or the return value of STD:: move().

If we don’t delve into it, we just need to know the difference between left value and right value. The detailed classification of right values does not need to be studied.

2.2 left value reference and right value reference

Lvalue reference is a general reference, which is generally represented by a &, for example

const A &a_ ref = a; //  Get the reference of object a

An lvalue reference is equivalent to an alias and points to a specific object.

rvalue reference

As the name suggests, an R-value reference is a reference to an R-value, which is represented by & &;
A &&r_ ref = getRvalue(); // r_ Ref is an R-value reference
The right value reference is also equivalent to an alias. The difference from the left value is that the right value reference is an alias of an unknown variable.

Getrvalue () is a function that returns an R-value. The R-value should end its lifetime after the execution of this sentence. If it is an object, it should call the destructor; But = = the right value reference makes it forcibly renew = =; Use the right value reference to point to the right value. The lifetime of the right value is as long as that of the right value reference, which reduces the destruction and construction of the object.

The R-value reference of C + + has two main uses, one is mobile semantics, and the other is perfect forwarding. This will be discussed in the next two articles.

summary

In order to import the right value and move semantics, first review the following temporary objects, and construct them several times when passing function return values and parameters; Then it compares and introduces the left value and right value, as well as the form and meaning of right value reference. Pave the way for the introduction of mobile semantics and perfect forwarding.

reference material

Michael Wang | IBM XL compiler, China, in-depth understanding of C + + 11, China Machine Press

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support developpaer.

Recommended Today

Why is reids fast

1. What is redis? Redis is completely open source and complies with the BSD protocol. It is a high-performance key value database. Redis is also one of the most popular NoSQL databases at present. It contains a variety of data structures, supports network, is memory based, and has an optional key value pair storage database […]