Search code examples
c++rvalue-referencedynamic-binding

Question about the usage of std::move() in member overloading


This question comes from C++ Primer(5th Edition), the last topic Simulating Virtual Copy in Chapter 15.

Define two classed related by inheritance:

class Quote{
public:
virtual Quote* clone() const & {return new Quote(*this);}
virtual Quote* clone() && {return new Quote(std::move(*this));}
//other members
};

class Bulk_quote: public Quote{
public:
Bulk_quote* clone() const& {return new Bulk_quote(*this);}
Bulk_quote* clone() && {return new Bulk_quote(std::move(*this));}
//other members
    };

and a class employing them:

class {
public:
  void add_item(const Quote& sale)   //copy the given object
    { items.insert(std::shared_ptr<Quote>(sale.clone()));}
  void add_item(Quote&& sale)  //move the given object
    {items.insert(std::shared_ptr<Quote>(std::move(sale).clone()));}
//other memebers
private:
  static bool compare(const std::shared_ptr<Quote>& lhs,const std::shared_ptr<Quote>& rhs)
{return lhs->isbn() < rhs->isbn();}
std::multiset<std::shared_ptr<Quote>,decltype(compare)*> items(compare);
};

I am stuck in two observations:

(1) why std::move(*this) in definition of member virtual Quote* clone()&& ? To my understanding, this version can only be run on a modifiable rvalue(say, temporal objects) under the reference qualifier &&. May std::move(*this) be replaced by *this?

(2)Similar to (1), why std::move(sale) in the second definition of member add_item which can only be run on a object of rvalue. For rvalue reference Quote&& sale can only be bound to a rvalue, is std::move(sale) necessary?

For calling the second version of add_item, the book says "although the type of sale is an rvalue reference type, sale(like any other variable) is an lvalue". However, the verison void add_item(const Quote& sale) will be called if sale is an lvalue. Who can help me out?


Solution

  • You seem confusing objects with expressions. Value category (lvalue or rvalue) is a property of an expression, not of an object, so even if, for example, *this refers to a temporary object, it as an expression is still an lvalue. So is sale.

    There are complicated rules to determine whether an expression is an lvalue or rvalue. The related rules for your example are:

    • expression of the form *expr is always an lvalue;

    • an unqualified name of a variable as an expression is always an lvalue.