Why was the move std :: string constructor not called?

I have this example:

#include <string> #include <iostream> class Test { private: std::string str; public: Test(std::string &&str_) : str(str_) {} const std::string &GetStr() { return str; } }; int main(int argc, char *argv[]) { std::string there("1234567890"); std::cout << "1. there: " << there << '\n'; Test t1(std::move(there)); std::cout << "2. there: " << there << '\n'; std::cout << "3. there: " << t1.GetStr() << '\n'; } 

He outputs

 $ ./a.out 1. there: 1234567890 2. there: 1234567890 3. there: 1234567890 

This uses gcc 5.1.1 for linux. Although the string there remains in a valid but undefined state after the move, this implementation seems to move (rather than copy) the string if the move constructor std :: string is called.

if I replaced the initializer str(str_) with str(std::move(str_)) , I get this output:

 $ ./a.out 1. there: 1234567890 2. there: 3. there: 1234567890 

This suggests that the std :: string move constructor is now used, but why isn't std::string(std::string &&) called in my first example?

+7
c ++
source share
2 answers

You have to do

 public: Test(std::string &&str_) : str(std::move(str_)) {} 

str_ have a name is a named object, so it will not be passed to any function as an rvalue reference.

The choice of design made by the standard committee forbids it to be considered as an rvalue, so you cannot accidentally change it. In particular: the str_ do type is an lvalue reference to a string , but str_ not considered an rvalue, because it is a named object.

You must make your intent explicit by adding a call to std::move . This means that you want str_ be an rvalue value, and you know all the consequences of this choice.

+6
source share

Because lvalue-reference always wins! Therefore, you need to explicitly specify std::move .

It is allowed to create links to links through the manipulation type in templates or typedefs, in which case the link applies folding rules: rvalue refers to rvalue reference collapses for rvalue links, all other combinations form an lvalue link:

 typedef int& lref; typedef int&& rref; int n; lref& r1 = n; // type of r1 is int& lref&& r2 = n; // type of r2 is int& rref& r3 = n; // type of r3 is int& rref&& r4 = 1; // type of r4 is int&& 

Taken from here .

+3
source share

All Articles