Reputation: 10539
I'm surprised that s and s2 internal pointer to "sample" are not equal, what is the explanation ?
#include <string>
#include <cassert>
int main()
{
std::string s("sample");
std::string s2(std::move(s));
assert(
reinterpret_cast<int*>(const_cast<char*>(s.data())) ==
reinterpret_cast<int*>(const_cast<char*>(s2.data()))
); // assertion failure here
return 1;
}
Upvotes: 3
Views: 1893
Reputation: 545963
Why do you assume that they should be the same? You are constructing s2
from s
using its move constructor. This transfers the data ownership from s
over to s2
and leaves s
in an “empty” state. The standard doesn’t specify in detail what this entails, but accessing s
’s data after that (without re-assigning it first) is undefined.
A much simplified (and incomplete) version of string
could look as follows:
class string {
char* buffer;
public:
string(char const* from)
: buffer(new char[std::strlen(from) + 1])
{
std::strcpy(buffer, from);
}
string(string&& other)
: buffer(other.buffer)
{
other.buffer = nullptr; // (*)
}
~string() {
delete[] buffer;
}
char const* data() const { return buffer; }
};
I hope that shows why the data()
members are not equal. If we had omitted the line marked by (*)
we would delete the internal buffer twice at the end of main
: once for s
and once for s2
. Resetting the buffer
pointer ensures that this doesn’t happen.
Upvotes: 3
Reputation: 56903
Each std::string
has its own buffer that it points to. The fact that you moved one from the other doesn't make it share one buffer. When you initialize s2
, it takes over the buffer from s
and becomes the owner of that buffer. In order to avoid s
to "own" the same buffer, it simply sets s
's buffer to a new empty one (and which s
is responsible for now).
Technically, there are also some optimizations involved, most likely there isn't a real buffer that got explicitly allocated for empty or very small strings, but instead the implementation of std::string
will use a part of the std::string
's memory itself. This is usually known as the small-string-optimization in the STL.
Also note that s
has been moved away, so the access of your code to it's data is illegal, meaning it could return anything.
Upvotes: 3
Reputation: 726929
You should not use the moved-from string
before replacing its value with some known value:
The library code is required to leave a valid value in the argument, but unless the type or function documents otherwise, there are no other constraints on the resulting argument value. This means that it's generally wisest to avoid using a moved from argument again. If you have to use it again, be sure to re-initialize it with a known value before doing so.
The library can stick anything it wants into the string, but it's very likely that you would end up with an empty string. That's what running an example from cppreference produces. However, one should not expect to find anything in particular inside a moved-from object.
Upvotes: 2