I was wondering in what kind of cases it makes sense to use move semantics when overloading operator+ and/or operator+=. Even though it is explained in this question how one could do this, I can't wrap my head around as to why I'd do it. Let's consider operator+=. If I just pass right hand side by reference and make the appropriate changes on the left hand side object, there are no unnecessary copies anyway. So we come back to the same point: Would move semantics be beneficial in such a case?
-
It's in general a bad idea to overload operators. Because: **1)** if it is obviously a good case to do so, there's probably a library already implementing it for you. **2)** if it isn't obviously a good case to do so, it's probably a very bad case to do it. – enobayram Mar 24 '12 at 11:03
-
3@enobayram make it an `append` member function if you're squicky around overloaded operators. Now you can still answer the question. – R. Martinho Fernandes Mar 24 '12 at 11:05
-
7@enobayram, that makes no sense at all. On that logic, it's generally a bad idea to write code, of any kind, ever. – TonyK Mar 24 '12 at 11:38
-
@enobayram: depends. I might agree for `+` (though, why should I not be writing a numeric or matrix library ?) but `<<` and `>>` is just idiomatic C++ for streams. – Matthieu M. Mar 24 '12 at 11:41
-
@TonyK it's generally a bad idea to write code that's already written. – enobayram Mar 24 '12 at 11:47
-
@MatthieuM. There are very nice and permissive open source matrix library implementations around, and that's one of the best examples of type **1)** , as for `<<` and `>>` that's a special case where you overload the operators to conform to the library (pseudo case **1)** ) – enobayram Mar 24 '12 at 11:49
-
@enobayram: so ? Just because there is a library out there does not mean I don't want to write my own. Reuse is good, but it brings neither understanding nor improvement. I understand your general sentiment, but beware of sweeping generalizations. – Matthieu M. Mar 24 '12 at 14:04
-
@MatthieuM. You're right, my generalization could be taken too far. I just wanted to point out that operator overloading in C++ is one of those things like using raw arrays, or managing the lifetime of an object in irregular ways that you should ask yourself "do I really need to do this?" several times before doing. – enobayram Mar 24 '12 at 14:53
-
@enobayram: I agree, I've seen many misuses, and I committed a few myself in my younger years ^^ – Matthieu M. Mar 24 '12 at 16:55
2 Answers
Yes and no.
operator+=
Move semantics are not necessarily helpful for operator+=
in general, because you are already modifying the left hand side argument (this
), so you already have resources to work with most of the times.
Still, as an optimization, it might be worth it. Imagine a std::string
implementation whose default constructor does not allocate any memory. Then std::string::operator+=(std::string&&)
could simply steal the resources from RHS. Or imagine that the RHS buffer is big enough to hold everything but the LHS is not, then if you can use the RHS buffer you're golden: just swap and prepend.
So, it may be worth it, but you have to study it. Therefore:
T& T::operator+=(T const&)
: always presentT& T::operator+=(T&&)
: to enable move semantics when it makes sense
operator+
Here it is always useful (providing we are talking about classes for which move semantics are useful).
The thing is, operator+
produces a temporary (out of the blue) so it generally has to create resources for this temporary. However if it can steal them rather than create them, it's certainly cheaper.
However, you need not provide all overloads:
T operator+(T const&, T const&)
T operator+(T&&, T const&)
T operator+(T const&, T&&)
T operator+(T&&, T&&)
(required for disambiguation)
No, you can reuse the same trick that operator=
use and create the temporary right in the function signature (by taking one argument by copy). If the type is movable, the move constructor will get called, otherwise it'll be the copy constructor, but since you need the temporary anyway, no loss of performance.
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(T const& left, T right) { right += left; return right; } // commutative
inline T operator+(T left, T&& right) { left += right; return left; } // disambiguation
Not much of a gain (3 instead of 4) but well, I'll take what I can!
Of course, for string, operator+
is not commutative (which is why it is a bad overload), so the actual implementation of the second overload would require a prepend
method.
EDIT: following Move semantics and operator overloading it seems that I was a bit over-enthusiastic. Stealing from Ben Voigt's answer, we get:
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(const T& left, T&& right) { right += left; return right; }
On the other hand, this seems to only work for commutative operations; -
does not work that way but can probably be adapted, /
and %
on the other hand...

- 1
- 1

- 287,565
- 48
- 449
- 722
-
Better do `right += left; return right;` to make it consider `right` as an rvalue when returning. – Johannes Schaub - litb Mar 24 '12 at 14:19
-
@JohannesSchaub-litb: May I suppose that you are talking about the last case ? I wondered about this too, and whether having a `T&& T::operator+()&&` overload was worth it. – Matthieu M. Mar 24 '12 at 16:32
-
I'm talking about all three cases. If `T` has a move constructor, you could make use of it by returning `left` or `right` respectively. As it is now with your code, if `operator+=` returns `T&`, you will always copy the parameter into the return value instead of moving it. – Johannes Schaub - litb Mar 24 '12 at 17:02
-
1Just to clarify; Did you update the answer according to @JohannesSchaub-litb's comments? I am a little confused. – iheap Mar 25 '12 at 08:54
-
@iheap: yes I did. To explain, if you do `return left += right;` because `+=` returns a `T&` (with no assurance of it referring to `this`) it might trigger a copy instead of a move. You thus have the choice of either going for `return std::move(left += right);` or `left += right; return left;`. In the first case the `std::move` is explicit, in the second case because `left` is a temporary the compiler knows it can "steal" from it. Another alternative would be to have a `T&& T::operator+=(...) &&` serie of overloads to cater for the left hand side being a temporary. It might be preferred. – Matthieu M. Mar 25 '12 at 12:46
-
1@BenVoigt: Right, however there is something that's bothering me. All the examples are done with commutative operations, but not all operations are commutative. Already it frays at the seams with `operator-`, and really falls apart with `/` and `%`. – Matthieu M. Apr 22 '13 at 06:21
-
@MatthieuM.: Right, because with `-` you can (usually) do `right = -right; right += left;`. And with `/` possibly `right = recip(right); right *= left;`. But `%` doesn't work. Or `<<` or `>>`. For those you just leave off the second overload and don't care whether the right operand is an rvalue-reference or not. – Ben Voigt Apr 22 '13 at 06:24
-
@MatthieuM. it would be great to know if this answer is still valid now or there are up to date informations. – Moia Apr 18 '18 at 13:33
-
1@Moia: There was no change to the move semantics or operators that I know of which would impact this answer; so I would expect it to be accurate still (for better or worse). Still, I guess 2 operators is not too bad. – Matthieu M. Apr 18 '18 at 15:16
If you're appending two strings, vectors etc. that you cannot "move", it doesn't make sense. But if you're appending, say linked lists, where appending the list is possibly an O(1) operator, if you're willing to sacrifice the right hand side, then it makes sense.

- 4,650
- 23
- 36