3

I was programming some test cases an noticed an odd behaviour.

An move assignment to a string did not erase the value of the first string, but assigned the value of the target string.

sample code:

#include <utility>
#include <string>
#include <iostream>

int main(void) {
  std::string a = "foo";
  std::string b = "bar";
  std::cout << a << std::endl;
  b = std::move(a);
  std::cout << a << std::endl;

  return 0;
}

result:

$ ./string.exe
foo
bar

expected result:

$ ./string.exe
foo

So to my questions:

  • Is that intentional?
  • Does this happen only with strings and/or STL objects?
  • Does this happen with custom objects (as in user defined)?

Environment: Win10 64bit msys2 g++ 5.2

EDIT

After reading the possible duplicate answer and the answer by @OMGtechy i extended the test to check for small string optimizations.

#include <utility>
#include <string>
#include <iostream>
#include <cinttypes>
#include <sstream>

int main(void) {
  std::ostringstream oss1;
  oss1 << "foo ";
  std::ostringstream oss2;
  oss2 << "bar ";
  for (std::uint64_t i(0);;++i) {
    oss1 << i % 10;
    oss2 << i % 10;
    std::string a = oss1.str();
    std::string b = oss2.str();
    b = std::move(a);
    if (a.size() < i) {
      std::cout << "move operation origin was cleared at: " << i << std::endl;
      break;
    }
    if (0 == i % 1000)
      std::cout << i << std::endl;
  }

  return 0;
}

This ran on my machine up to 1 MB, which is not a small string anymore. And it just stopped, so i could paste the source here (Read: i stopped it).

scones
  • 3,317
  • 23
  • 34
  • 1
    You are incorrectly assuming that a moved object will be in a "default" or empty state, objects that have been moved from can be in **any** valid state, in this case your implementation has simply swapped the values. – user657267 Apr 05 '16 at 09:50

1 Answers1

0

This is likely due to short string optimization; i.e. there's no internal pointer to "move" over, so it ends up acting just like a copy.

I suggest you try this with a string large number of characters; this should be enough to get around short string optimization and exhibit the behaviour you expected.

This is perfectly valid, because the C++ standard states that moved from objects (with some exceptions, strings are not one of them as of C++11) shall be in a valid but unspecified state.

OMGtechy
  • 7,935
  • 8
  • 48
  • 83
  • but it didn't copy: it appears to have swapped the strings instead. That's also a valid way to move, since the final state of the moved-from object is unspecified; it only needs to be capable of being destroyed or reassigned. It's possible the implementor found it easier to swap the 2 instances, without clearing the source along the way, and that's no less valid, if a bit unexpected. – underscore_d Sep 13 '18 at 09:44