Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If I move a local object into a function, will it still be valid afterward?

So, this provides the intended output:

void f(std::string&& s)
{
   s += " plus extra";
}

int main(void)
{
   std::string str = "A string";
   f( std::move(str) );
   std::cout << str << std::endl;

   return 0;
}

A string plus extra

That is, it works when I run it on Ideone, but is it UB? Adding extra string initializations before and after the call to f didn't change anything.

like image 678
Matt Avatar asked Mar 25 '16 18:03

Matt


People also ask

What happens to object after std :: move?

std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.

Can you return a local object in C++?

If a method or function returns a local object, it should return an object, not a reference. If a method or function returns an object of a class for which there is no public copy constructor, such as ostream class, it must return a reference to an object.

What happens STD move?

std::move itself does "nothing" - it has zero side effects. It just signals to the compiler that the programmer doesn't care what happens to that object any more. i.e. it gives permission to other parts of the software to move from the object, but it doesn't require that it be moved.

What does do not rely on value of moved from an object?

Do not rely on the value of a moved-from object unless the type of the object is documented to be in a well-specified state. While the object is guaranteed to be in a valid state, relying on unspecified values leads to unspecified behavior.


2 Answers

It is valid, not UB.

It is also horribly obfuscated code. std::move(s) is nothing but a cast to rvalue. By itself it does not actually generate any code at all. Its only purpose is to turn an lvalue into an rvalue so that client code can overload on lvalue/rvalue expressions (of string in this case).

You should pass by lvalue-reference for this case:

void f(std::string& s)
{
   s += " plus extra";
}
...
f( str );

Or alternatively, pass by value and return a new string:

std::string f(std::string s)
{
   s += " plus extra";
   return s;
}
...
str = f( std::move(str) );
like image 184
Howard Hinnant Avatar answered Oct 17 '22 07:10

Howard Hinnant


std::move doesn't move anything. It indicates that an object may be "moved from", by casting its argument to an rvalue.

Your code is valid and there is no move operation performed.

You would get the behavior where the state of str is unspecified after calling f(), if you move-construct another string object from s. The move-constructor performs the actual move operation.

Example:

std::vector<std::string> sv;

void f(std::string&& s)
{
    s += " plus extra";
    sv.push_back(std::move(s));         // move s (str) into a new object
}

int main(void)
{
   std::string str = "A string";
   f(std::move(str));                 
   std::cout << str << std::endl;       // output: empty string
   std::cout << sv.back() << std::endl; // output: "A string plus extra"

   return 0;
}
like image 44
sergej Avatar answered Oct 17 '22 06:10

sergej