简体   繁体   中英

Behaviour of std::move operation in c++11

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

struct A {
    std::string s;
    A() : s("test") {}
    A(const A& o) : s(o.s) { std::cout << "move failed!\n"; }
    A(A&& o) : s(std::move(o.s)) {}
    A& operator=(const A&) { std::cout << "copy assigned\n"; return *this; }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << "move assigned\n";`enter code here`
        return *this;
    }
};

A f(A a) { return a; }

struct B : A {
    std::string s2;
    int n;
    // implicit move assignment operator B& B::operator=(B&&)
    // calls A's move assignment operator
    // calls s2's move assignment operator
    // and makes a bitwise copy of n
};

struct C : B {
    ~C() {}; // destructor prevents implicit move assignment
};

struct D : B {
    D() {}
    ~D() {}; // destructor would prevent implicit move assignment
    //D& operator=(D&&) = default; // force a move assignment anyway 
};

int main()
{
    A a1, a2;
    std::cout << "Trying to move-assign A from rvalue temporary\n";
    a1 = f(A()); // move-assignment from rvalue temporary
    std::cout << "Trying to move-assign A from xvalue\n";
    a2 = std::move(a1); // move-assignment from xvalue

    std::cout << "Trying to move-assign B\n";
    B b1, b2;
    std::cout << "Before move, b1.s = \"" << b1.s << "\"\n";
    b2 = std::move(b1); // calls implicit move assignment
    std::cout << "After move, b1.s = \"" << b1.s << "\"\n";

    std::cout << "Trying to move-assign C\n";
    C c1, c2;
    c2 = std::move(c1); // calls the copy assignment operator

    std::cout << "Trying to move-assign D\n";
    D d1, d2;
//  d2 = std::move(d1);
}

While executing a2 = std::move(a1) statement, the behaviour is different from executing the statement b2 = std::move(b1) . In the below statement the b1.s is not becoming empty after the move operation while a1.s is becoming empty after move operation.

Can anyone tell what exactly is happening there?

One of the great (and constant) misconceptions about C++11 and rvalue references is that std::move does something to an object (or something on that order).

It doesn't. std::move really just casts its parameter to rvalue reference type and returns that. Anything done to the object happens in the move constructor, move assignment operator (etc.) based on the fact that the version that takes an rvalue reference is invoked (instead of one taking a value or lvalue reference).

As far as the specific question you asked goes, at least based on the comments in your code, you seem to have some misunderstandings. The comment on a2=std::move(a1); says you're doing a "move assignment from an xvalue". That's...misleading at best. An xvalue is a value that's going to eXpire immediately. It's pretty much for the return value from a function:

Foo &&bar() { 
    Foo f;
    // ...
    return f;
}

In this case, bar() is an xvalue because bar returns an rvalue reference to an object that expires (goes out of scope) as function finishes execution.

As far as the specific question you asked goes, I suspect it mostly comes down to a question of whether (and if so, exactly how) your standard library implements the move constructor for std::string . Just for example, when using g++ (4.9.1) I get the same result you do-- b1.s contains test both before and after being used as the source of a move. On the other hand, if I use MS VC++ 14 CTP, I get b1.s="test" before the move and b1.s="" after the move. Although I haven't tested it, I'd expect results with Clang to be the same. In short, it looks like gcc's standard library doesn't really implement move assignment/construction for std::string (yet--at least as of v 4.9--I haven't looked at 5.0 yet).

Usually move assignment is implemented as a swap on std::string , so why should the string become empty since it's always initialized with "test" ?

Where do you see that a1.s is becoming empty since there is no print of it?

I don't see any strange behavior here . Both are treated in the same way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM