Reprinted from www.cnblogs.com/catch/p/350…

Lvalue and rvalue are obscure and basic concepts in C/C ++. Some people may not even have heard of them, but they become very important in C ++11. They are the basis for understanding new semantics such as move and forward.

Definition of an lvalue and rvalue

int a; int b; a = 3; b = 4; a = b; b = a; // The following is not legal. = a; a+b = 4;Copy the code

In C, variables with names are usually lvalues (a, b in the example above), and intermediate results (without names) produced by operations (addition, subtraction, multiplication, division, return values from function calls, etc.) are rvalues (3 + 4, a + b, etc.). We can think of an lvalue as something that can be found in a program, and an rvalue as something whose address cannot be retrieved (not exactly), but the concept becomes slightly different in c++.

Specifically, in c++, every expression produces an lvalue, or rvalue, which is called an “lvalue expression”, “rvalue expression”. For primitive types, the concept of lvalue and rvalue is not that different from C. The difference is in the custom type, and the difference can be confusing:

1) For built-in types, right values cannot be modifiable (non-modifiable), nor can they be modified by const, volatile (CV-qualitification) ignored.

2) For user-defined types, an rvalue allows modification through its member functions.

For 1), this is consistent with C, and 2) is unique to C++, so don’t be surprised if you see C++ written like this:

class cs { public: cs(int i): i_(i) { cout << "cs(" << i <<") constructor!" << endl; } ~cs() { cout << "cs destructor,i(" << i_ << ")" << endl; } cs& operator=(const cs& other) { i_ = other.i_; cout << "cs operator=()" << endl; return *this; } int get_i() const { return i_; } void change(int i) { i_ = i; } private: int i_; }; cs get_cs() { static int i = 0; return cs(i++); } int main () {/ / legal (get_cs () = cs (2)). The change (323); get_cs() = cs(2); // operator=() get_cs().change(32); return 0; }Copy the code

This may seem a bit strange, because custom types are usually designed to look as much like built-in types (so-called value types), but this feature intentionally or unconsciously makes custom types special. Calling a member function from an rvalue is allowed. However, a member function may not be const, so calling an rvalue may modify the rvalue, done!

Lvalue reference, rvalue reference

In terms of rvalues, there was a notable feature of the language prior to c++11 that an rvalue could be pointed to by a reference to const, so the following code is legal.

const cs& ref = get_cs();Copy the code


// error 
cs& ref = get_cs();Copy the code

When an rvalue is referred to by a const reference, its lifetime is extended, a usage I described in a previous blog post. The underlying logic is that an rvalue cannot be used as an lvalue (but an lvalue can be used as an rvalue).

It is also worth noting that for the two properties of rvalues mentioned earlier:

1) Allow calling member functions.

2) Can only be referred to by const reference.

They lead to some interesting results, such as:

void func(cs& c) { cout << "c:" << c.get_i() << endl; } //error func(get_cs()); Func (get_cs() = get_cs());Copy the code





class cs { public: cs& operator=(const cs& c); }; Class cs2 {public: cs2&operator =(cs2&c); };Copy the code





Auto_ptr class auto_ptr {public: auto_ptr(auto_tr& p) {ptr_ = p.ptr_; p.ptr_ = NULL; } private: void* ptr_; };Copy the code


// error auto_ptr p(get_ptr()); // operator=() Similarly, error. auto_ptr p = get_ptr();Copy the code