I was investigating the performance of moving std::string
. For the longest time, I've regarded string moves as almost free, thinking the compiler will inline everything and it will only involve a few cheap assignments.
In fact, my mental model for moving is literally
string& operator=(string&& rhs) noexcept
{
swap(*this, rhs);
return *this;
}
friend void swap(string& x, string& y) noexcept
{
// exposition only
unsigned char buf[sizeof(string)];
memcpy(buf, &x, sizeof(string));
memcpy(&x, &y, sizeof(string));
memcpy(&y, buf, sizeof(string));
}
To the best of my understanding, this is a legal implementation if the memcpy
is changed to assigning individual fields.
It is to my great surprise to find gcc's implementation of moving involves creating a new string and might possibly throw due to the allocations despite being noexcept
.
Is this even conforming? Equally important, should I not think moving is almost free?
Bewilderingly, std::vector<char>
compiles down to what I'd expect.
clang's implementation is much different, although there is a suspicious std::string::reserve
memcpy
. At the very least, I'd expect a buffer of sizesizeof(string)
for temporarily copying the contents of the array to and from, not the creation of a temporary string – Jodiejodofoo
. I believe the whole thing will collapse down at that point to a few memory operations, like you expect. I can't explain why the produced assembly appears to so much stuff. – Lignifyfoo
is the best way I can think of to isolate and use the move. The parameters are only references and won't have any constructor/destructor. The function is global with side effects and must be compiled to something. – Jodiejodostd::string
is explicitlynoexcept
as verified by thestatic_assert
. Also explains the call tostd::terminate
in clang's output. – Jodiejododata()
should be a non null pointer. – Aneroidographdata
. That's what "unspecified value" means. – Esophagitisbasic_string::__clear_and_shrink()
should be markednoexcept
. With that addition the move assignment operator cleans up pretty nicely. – Duthiebasic_string::reserve
call that with an argument of0
? I didn't see abasic_string::__clear_and_shrink
there – Jodiejodo__clear_and_shrink
is evidently a recent edit. I was looking at the tip-of-trunk libc++: github.com/llvm-mirror/libcxx/blob/master/include/… – Duthie