2

I have seen this quote from an original article:

When we run sorted on an rvalue, it is safe to sort the data member directly. The object is an rvalue, which means it has no other users, so we can change the object itself. When we run sorted on a const rvalue or on an lvalue, we can’t change this object, so we copy data before sorting it

It said that a rvalue (temporary) can sort itself because it has no user. An lvalue cannot sort itself (sort a copy of it) because it maybe has users.

What is a user of lvalue? And what's the background?

Here is some code exemplifying the situation.

#include <vector>
#include <algorithm>

using namespace std;

class Foo {
public:
    Foo() { std::cout << "default construct" << std::endl;}
    Foo(const Foo &f) : data(f.data) {std::cout << "copy construct" << std::endl;}
    Foo sort() &&;
    Foo sort() const &;
private:
    vector<int> data;
};

Foo Foo::sort() && {
    std::cout << "rvalue sort" << std::endl;
    std::sort(data.begin(), data.end());
    return *this;
}

Foo Foo::sort() const & {
    std::cout << "lvalue sort" << std::endl;
    return Foo(*this).sort();
}
JaMiT
  • 14,422
  • 4
  • 15
  • 31
Zhen Yang
  • 83
  • 9

1 Answers1

0

An rvalue reference is an object that is meant to be no longer referenced. Since the object is no longer referenced, anything the object holds can be mutated or moved to another object without affecting any existing reference to the object (it's no longer referenced). This allows for move semantics, which means data that would normally have to be copied to another object can be moved instead.

So, using the example code you gave...

int main(int argc, char *argv[]) {  

  Foo x, y, z;

  std::cout << "lvalue" << std::endl;

  y = x.sort();

  std::cout << "rvalue reference" << std::endl;

  z = Foo().sort();

  return 0;
}

we have

default construct
default construct
default construct
lvalue
lvalue sort
copy construct
rvalue sort
copy construct
rvalue reference
default construct
rvalue sort
copy construct

What happens first is an lvalue which has its sort method called, which is copied and becomes and rvalue reference which is then sorted.

What happens second is that the object default constructed doesn't have a name, so it can be treated as an rvalue reference. So, the rvalue reference sort method is called directly.

Jason
  • 3,777
  • 14
  • 27
  • Thanks for the detailed explanation. Actually I know what has been done to rvalue foo sort and lvalue foo sort. It's the concept of "lvalue user" and "lvalue cannot sort itself" makes me confuse. Thanks again. – Zhen Yang Oct 17 '19 at 03:47
  • @ZhenYang The difference between the two values you have are that one has a name (`lvalue`) and the other does not (`rvalue` reference). The `rvalue` reference is not meant to be referenced whereas the `lvalue` can still be referenced since it has a name. – Jason Oct 17 '19 at 04:10
  • Do you mean that an lvalue might be referenced by others (they are the users). So if the lvalue can sort itself, other users cannot be aware of the change? – Zhen Yang Oct 17 '19 at 05:49
  • @ZhenYang An `lvalue` can still have references which an `rvalue` reference is not supposed to. So, mutating state in an `lvalue` could be visible since there can still be references. Still, nothing in the language prevents an `lvalue` from mutating itself, but it could be visible to objects that still hold references which is not like an `rvalue` reference. – Jason Oct 17 '19 at 08:14