问题
According to this cppreference page, passing the first argument of an overloaded binary operator by value somehow optimizes expressions like a + b + c
. The relevant code snippet from the linked page is as follows:
class X
{
public:
X& operator+=(const X& rhs) // compound assignment (does not need to be a member,
{ // but often is, to modify the private members)
/* addition of rhs to *this takes place here */
return *this; // return the result by reference
}
// friends defined inside class body are inline and are hidden from non-ADL lookup
friend X operator+(X lhs, // passing lhs by value helps optimize chained a+b+c
const X& rhs) // otherwise, both parameters may be const references
{
lhs += rhs; // reuse compound assignment
return lhs; // return the result by value (uses move constructor)
}
};
I have 2 questions regarding this:
- How are chained
a + b + c
expressions optimized by this? - Assuming
X
also overrides the copy and move assignment operators and constructors, would a statement likex = a + b
produce any copying? Why or why not?
回答1:
I don't know whether this had that example-writer in mind, but have some explanation. Consider what happens in this code:
X a, b, c;
X d = a + b + c;
Here, first, a + b
is evaluated basically as operator+(operator+(a, b), c)
. Note that operator+(a, b)
is an rvalue, and therefore, lhs
can, in the outer application of operator+
, be initialized by move-constructor.
An alternative how to implement operator+
in terms of operator+=
is as follows:
friend X operator+(const X& lhs, const X& rhs)
{
X temp(lhs);
temp += rhs;
return temp;
}
Note that you need to create a temporary since you need an object to apply operator+=
on. With this solution, both applications of operator+
in operator+(operator+(a, b), c)
involves copy-constructor.
Live demo: https://godbolt.org/z/5Dq7jF
Of course, you can add a second version for rvalues as follows:
friend X operator+(X&& lhs, const X& rhs)
{
lhs += rhs;
return std::move(lhs);
}
But this requires much more typing than the original value-passing version.
Generally, passing by value is frequently used in situations where you want to unify overloads for lvalues and rvalues; for example, look for unified assignment operator.
来源:https://stackoverflow.com/questions/62177743/why-does-cannonical-implementation-of-overloading-binary-arithmatic-operator-in