I have a very basic question in C++. How to avoid copy when returning an object ?
Here is an example :
std::vector<unsigned int> test(const unsigned int n) { std::vector<unsigned int> x; for (unsigned int i = 0; i < n; ++i) { x.push_back(i); } return x; }
As I understand how C++ works, this function will create 2 vectors : the local one (x), and the copy of x which will be returned. Is there a way to avoid the copy ? (and I don't want to return a pointer to an object, but the object itself)
What would be the syntax of that function using "move semantics" (which was stated in the comments)?
If a function returns a reference, and that reference is used to initialize or assign to a non-reference variable, the return value will be copied (as if it had been returned by value).
Returning an object invokes the copy constructor while returning a reference doesn't. So, the version #2 does less work and is more efficient. The reference should be to an object that exists when the calling function is execution.
In lieu of a data type, void functions use the keyword "void." A void function performs a task, and then control returns back to the caller--but, it does not return a value. You may or may not use the return statement, as there is no return value.
It means you return by reference, which is, at least in this case, probably not desired. It basically means the returned value is an alias to whatever you returned from the function. Unless it's a persistent object it's illegal.
There seems to be some confusion as to how the RVO (Return Value Optimization) works.
A simple example:
#include <iostream> struct A { int a; int b; int c; int d; }; A create(int i) { A a = {i, i+1, i+2, i+3 }; std::cout << &a << "\n"; return a; } int main(int argc, char*[]) { A a = create(argc); std::cout << &a << "\n"; }
And its output at ideone:
0xbf928684 0xbf928684
Surprising ?
Actually, that is the effect of RVO: the object to be returned is constructed directly in place in the caller.
How ?
Traditionally, the caller (main
here) will reserve some space on the stack for the return value: the return slot; the callee (create
here) is passed (somehow) the address of the return slot to copy its return value into. The callee then allocate its own space for the local variable in which it builds the result, like for any other local variable, and then copies it into the return slot upon the return
statement.
RVO is triggered when the compiler deduces from the code that the variable can be constructed directly into the return slot with equivalent semantics (the as-if rule).
Note that this is such a common optimization that it is explicitly white-listed by the Standard and the compiler does not have to worry about possible side-effects of the copy (or move) constructor.
When ?
The compiler is most likely to use simple rules, such as:
// 1. works A unnamed() { return {1, 2, 3, 4}; } // 2. works A unique_named() { A a = {1, 2, 3, 4}; return a; } // 3. works A mixed_unnamed_named(bool b) { if (b) { return {1, 2, 3, 4}; } A a = {1, 2, 3, 4}; return a; } // 4. does not work A mixed_named_unnamed(bool b) { A a = {1, 2, 3, 4}; if (b) { return {4, 3, 2, 1}; } return a; }
In the latter case (4), the optimization cannot be applied when A
is returned because the compiler cannot build a
in the return slot, as it may need it for something else (depending on the boolean condition b
).
A simple rule of thumb is thus that:
RVO should be applied if no other candidate for the return slot has been declared prior to the return
statement.
This program can take advantage of named return value optimization (NRVO). See here: http://en.wikipedia.org/wiki/Copy_elision
In C++11 there are move constructors and assignment which are also cheap. You can read a tutorial here: http://thbecker.net/articles/rvalue_references/section_01.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With