0

I'm currently studying move semantics in C++, and I faced an unexpected behavior. Here is a Test class with different constructors declared.

#include <iostream>
#include <string>
using namespace std;

class Test {

public:

    Test(const std::string &s = "") : s_(s) {
        cout << "Constructor " << s_ << endl;
    }

    Test(const std::string &&s) 
    : s_(std::move(s)) {
        cout << "Move constructor " << s_ << endl;
    }

    Test(const Test &t) {
        cout << "Copy " << t.s_ << " to " << s_ << endl;
        s_ = "copy " + t.s_;
    }

    Test(const Test &&t) noexcept 
    : s_(std::move(t.s_)) {
        cout << "Move " << t.s_ << " to " << s_ << endl;
    }

    Test& operator=(const Test &t) {
        cout << "operator= " << s_ << " = " << t.s_ << endl;
        s_ = "= " + t.s_;
        return *this;
    }

    ~Test() {
        cout << "Destructor " << s_ << endl;
    }

private:
    std::string s_;
};

And a piece of code to check, how move works:

int main() {
    Test t1{"1"};
    Test t2(std::move(t1));

    std::string str3("t3");
    Test t3(std::move(str3));
    cout << "str str3 after std::move " << str3 << endl;

    std::string sss("e");
    std::string fff(std::move(sss));
    cout << "str sss after std::move " << sss << endl;

    return 0;
}

After executing this code the output is:

    Move constructor 1
    Move 1 to 1
    Move constructor t3
    str str3 after std::move t3
    str sss after std::move 
    Destructor t3
    Destructor 1
    Destructor 1

So it seems that t1 and str3 variables still have it's values, though it should be absent after calling the move constructor in std::string the same way it happens with sss and fff in a case with strings, not aggregated to a class. But it seems that they're just copied.

Is there something I missed?

Evg
  • 25,259
  • 5
  • 41
  • 83
  • constructor (8) here https://en.cppreference.com/w/cpp/string/basic_string/basic_string, "other is left in valid, but unspecified state." – 463035818_is_not_an_ai May 12 '23 at 13:09
  • please do not remove includes from your code. They are part of the code. If someone wants to compile your code they will have to add them back in. – 463035818_is_not_an_ai May 12 '23 at 13:11
  • *"though it should be absent after calling the move constructor"* No there is no such guarantee. See [Can you reuse a moved std::string?](https://stackoverflow.com/questions/27376623/can-you-reuse-a-moved-stdstring) – Jason May 12 '23 at 13:18
  • You never invoke any move constructors in `Test` class. Passing a reference to `const` qualified string causes a copy constructor to be used instead. – user7860670 May 12 '23 at 13:19
  • [`std::move` doesn't actually move anything](https://stackoverflow.com/a/27026280/12002570). – Jason May 12 '23 at 13:19
  • One reason for this is the "short string optimization"; short strings are often stored in the `string` object itself rather than in dynamic memory, and emptying the "source" would be a waste of time. Try with a much longer string and you will see that the "source" has been emptied. – molbdnilo May 12 '23 at 13:42

0 Answers0