Reputation: 2164
The code below:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1 = "hello";
string s2 = "my";
string s3 = "world";
string s4;
s4 = move(s1) + move(s2) + move(s3);
cout << "s4(" << s4 << ") = s1(" << s1 << ") + s2(" << s2 << ") + s3(" << s3 << ")"<< endl;
}
gives the following output:
s4(hellomyworld) = s1() + s2(my) + s3(world)
Can you explain what is going on? (Tested with XCode 4.6.1)
EDIT:
I expected to see:
s4(hellomyworld) = s1() + s2() + s3()
Upvotes: 1
Views: 116
Reputation: 2089
s4 = move(s1) + move(s2) + move(s3)
is in fact operator=(s4, operator+(operator+(move(s1), move(s2)), move(s3));
The implementation of operator+
is not required to modify its rvalue argument, but is allowed. Presumably the implementation is something like this:
string operator+(string&& left, string&& right)
{
string result(left);
return result += right;
}
where right is only read.
Upvotes: 1
Reputation: 2164
template<class _CharT, class _Traits, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
basic_string<_CharT, _Traits, _Allocator>
operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs)
{
return _VSTD::move(__lhs.append(__rhs));
}
So seems like during the concatenation __rhs
s stayed unchanged. After all the string is accumulated at s1 the move assignment of s4 emptied s1.
Upvotes: 0
Reputation: 385295
I assume you expected s4(hellomyworld) = s1() + s2() + s3()
.
First of all, movement leaves the source object in "a valid state with an unspecified value" ([C++11: 21.4.2/2]
) — that is, you can't make any claims about what a string's value will be after you moved from it.
Secondly, std::move
is a misnomer, in that it doesn't actually move anything. Movement is implemented by swapping things around, and there is no guarantee that your string operator+
does anything of the sort (see jmihalicza's answer for a sample implementation); all std::move
does is obtain an rvalue reference that may be moved from.
[C++11: 21.4.6.3/1]
says about std::basic_string& assign(basic_string&& str) noexcept
(which is the function you're really invoking, when you follow all the breadcrumbs from operator+
) that "a valid implementation is swap(str)
", but that doesn't mean a swap has to occur.
Upvotes: 4