In C ++ 11, does the std :: string function return to the move or copy function?

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', are the data in mystr copied or moved to result ? I believe it has been moved around in C ++ 11 style, but I was hoping for clarifications and / or links to show this.

Thanks!

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

+7
c ++ c ++ 11
source share
5 answers

Your example refers to the so-called Name Returns Optimization, which is defined in this section of the C ++ 11 standard . Thus, the compiler can exclude the copy constructor (or move the constructor from C ++ 14). This exception is optional.

In C ++ 11, if the compiler does not fulfill this exception, the returned string will be built by the copy. The returned object will be moved if it called the function parameter [class.copy] / 32 (mine is in bold):

When the criteria for performing the copy operation are executed or are executed, except that the source object is a parameter of the function , and the object to be copied is denoted by lvalue, the overload resolution for selecting the constructor for the copy is first executed as if the object was designated rvalue . [...]

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

When the criteria for performing the copy / move operation are met, but not for declaring an exception, but the object to be copied is indicated by the value lvalue or when the expression in the return statement is (possibly in parentheses) an id expression that declares an object with an automatic storage duration declared in the body or parameter-declaration-sentence of the innermost include function or lambda expression, overload resolution to select the constructor for the copy is first executed as if the object was designated rvalue . [...]

So, in your code example and in C ++ 14, if the compiler fails to cope with the copy / move construct, the returned string will be built along the way.

+5
source share

Like user4581301, I suspect that in most implementations, the occurrence of a copy (rather than a transition) will occur. For C ++ 11 and C ++ 14, the standard allows copying, but does not give it a credential. In C ++ 17, some instances of the copy instance will be authorized. So, for C ++ 11 and C ++ 14, technically the answer depends on the implementation used. In your particular case, we are talking about a specific type of copy algorithm: return value optimization (RVO). To check if RVO exists in your environment for a 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 chooses RVO - no movement happens.

+2
source share

The way most compilers implement class type returns is to pass an additional β€œhidden” argument to a function, which is a pointer to the memory in which the return value should be built. Thus, the called function can copy or move the return value to this memory as necessary, without regard to the call site.

In your code example, such a compiler can even use the same memory to store the mystr variable, build it directly and never use the std :: string move or copy constructor.

0
source share

In my VS2015, the compiler is called move ctor when the temp variable returns in such a trivial case.

 class A { public: A(int _x) :x(_x) {} A(const A& a) { cout << "copy ctor." << endl; x = ax; } A(A&& a) { cout << "move ctor." << endl; x = 123; } private: int x; }; A foo() { A temp = { 7 }; return temp; //invoke move ctor } int main() { A a = foo(); return 0; } 

The relationship, whether the trigger of the RVO compiler depends on the copy price, you can see the RVO mechanism below: https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/RVO_V_S_std_move=lang=lang=lang=lang= en

0
source share

Since std::string result = foo(); is an initializer, it will call the constructor, not the assignment operator. In C ++ 11 or later, there is guaranteed to be a move constructor with the prototype std::basic_string::basic_string( basic_string&& other ) noexcept . In every real-life implementation, this moves the contents, not copies them. Although I do not believe that the standard provides for a specific implementation, he says that this particular operation should be performed in constant and non-linear time, which excludes a deep copy. Since the return value of foo() is a temporary rvalue, this is the constructor that will be called in this fragment.

So yes, this code will move the line, not copy it.

The expression in the return will not always be copied. If you return std::string("SOMELONGVALUE"); (software constructor), implementations are allowed to build the result instead. If foo() returns std::string& and returns something other than temporary, which will be returned by reference. (Returning a temporary reference that was destroyed is, as you know, undefined behavior!). And some compilers, even before C11, would do the copying and not create a temporary one just for copying and destruction. This is still allowed, and your compiler may or may not be able to apply it here.

0
source share

All Articles