Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In c++11, does returning a std::string in a function move or copy it?

Tags:

c++

c++11

suppose I have the following code.

std::string foo() {
    std::string mystr("SOMELONGVALUE");
    return mystr;
}

int main() {
    std::string result = foo();
}

When I call 'foo', is the data in mystr copied or moved into result? I believe that it is moved C++11 style, but I was hoping for clarification and/or links to show that.

Thanks!

Edit: I suppose I want to know the answer to this question when compiling with g++ for c++11 or later.

like image 266
mmnormyle Avatar asked Jan 09 '18 01:01

mmnormyle


People also ask

Does std::string make a copy?

std::string object will allocate internal buffer and will copy the string pointed to by ps there. Changes to that string will not be reflected to the ps buffer, and vice versa. It's called "deep copy".

Is std::string movable?

Yes, std::string (since C++11) is able to be moved i.e. it supports move semantics.

Does std :: move make a copy?

std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.

Should I return std :: move?

std::move is totally unnecessary when returning from a function, and really gets into the realm of you -- the programmer -- trying to babysit things that you should leave to the compiler.


2 Answers

Your example fall on the so-called Named Return Value Optimization, which is defined in this paragraph of the C++11 standard. So the compiler may elide the copy constructor (or move constructor since C++14). This elision is not mandatory.

In C++11, if the compiler does not perform this elision, the returned string will be copy constructed. The returned object would be moved if it were naming a function parameter, [class.copy]/32 (bold is mine):

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. [...]

In C++14, this last rule has changed. It also includes the case of automatic variables [class.copy]/32:

When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. [...]

So in your example code, and in C++14, if the compiler does not elide the copy/move construction, the returned string will be move constructed.

like image 73
Oliv Avatar answered Sep 26 '22 12:09

Oliv


Like user4581301 said, I suspect copy elision to happen (not a move) in most implementations. For c++11 and c++14, the standard allows copy elision to happen but doesn't mandate it. In c++17, some instances of copy elision will become mandated. So, for c++11 and c++14, technically the answer depends on the implementation being used. In your case specifically, we're talking about a specific type of copy elision: return value optimization (RVO). To check whether RVO happens in your environment for your given case, you can run this code:

#include <iostream>

struct Foo {
  Foo() { std::cout << "Constructed" << std::endl; }

  Foo(const Foo &) { std::cout << "Copy-constructed" << std::endl; }

  Foo(Foo &&) { std::cout << "Move-constructed" << std::endl; }

  ~Foo() { std::cout << "Destructed" << std::endl; }
};

Foo foo() {
    Foo mystr();
    return mystr;
}

int main() {
    Foo result = foo();
}

My implementation opts for RVO - no move takes place.

like image 45
sabee Avatar answered Sep 23 '22 12:09

sabee