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?
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.