vendredi 21 octobre 2016

Why move return an rvalue reference parameter need to wrap it with std::move()?

I was reading Effective Modern C++ Item 25, on page 172, it has an example to demonstrate that, if you want to move return an rvalue reference parameter, you need to wrap it with std::move(param). As parameter by itself is always an lvalue, if no std::move(), it will be copy returned.

I don't understand. If std::move(param) merely cast the parameter it takes in into an rvalue reference, then what's the difference when param is already an rvalue reference?

Like in the code below:

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

template<typename T>
class TD;

class Widget {
public:
    explicit Widget(const std::string& name) : name(name) {
        std::cout << "Widget created with name: " << name << ".\n";
    }

    Widget(const Widget& w) : name(w.name) {
        std::cout << "Widget " << name << " just got copied.\n";
    }

    Widget(Widget&& w) : name(std::move(w.name)) {
        std::cout << "Widget " << name << " just got moved.\n";
    }

private:
    std::string name;
};

Widget passThroughMove(Widget&& w) {
    // TD<decltype(w)> wType;
    // TD<decltype(std::move(w))> mwType;
    return std::move(w);
}

Widget passThrough(Widget&& w) {
    return w;
}

int main() {
    Widget w1("w1");
    Widget w2("w2");

    Widget wt1 = passThroughMove(std::move(w1));
    Widget wt2 = passThrough(std::move(w2));

    return 0;
}

It outputs:

Widget created with name: w1.
Widget created with name: w2.
Widget w1 just got moved.
Widget w2 just got copied.

In passThroughMove(Widget&& w), w's type is already rvalue reference, std::move(w) just cast it into rvalue reference again. If I uncomment the TD lines, I can see that of decltype(w) and decltype(std::move(w)) are both Widget &&:

move_parameter.cpp:27:21: error: implicit instantiation of undefined template 'TD<Widget &&>'
    TD<decltype(w)> wType;
                    ^
move_parameter.cpp:28:32: error: implicit instantiation of undefined template 'TD<Widget &&>'
    TD<decltype(std::move(w))> mwType;
                               ^

As both w and std::move(w) are same rvalue reference type, why "return std::move(w)" moves w, while "return w" only copy?

Aucun commentaire:

Enregistrer un commentaire