Does return statement copy values

C++Return

C++ Problem Overview


I am wondering about this because of scope issues. For example, consider the code

typedef struct {
	int x1;/*top*/
	int x2;/*bottom*/
	int id;
} subline_t;



subline_t subline(int x1, int x2, int id) {
	subline_t t = { x1, x2, id };
	return t;
}

int main(){
    subline_t line = subline(0,0,0); //is line garbage or isn't it? the reference
    //to subline_t t goes out of scope, so the only way this wouldn't be garbage
    //is if return copies
}

So my question is, will the return statement always copy? In this case it seems to work, so I am led to believe that return does copy. If it does copy, will it copy in every case?

C++ Solutions


Solution 1 - C++

Yes, in that case there will be a copy made. If you change the function declaration like this:

subline_t &subline(int x1, int x2, int id) {

then no copy will be made. However, in your specific case it would not be valid to return a reference to an object allocated on the stack. The problem is that the object would be destructed and invalidated before the caller had a chance to use it.

This is related to the common Return Value Optimization for C++ that can avoid doing an actual copy operation in the case you have described. The end result is (or should be) the same as if a copy were done, but you should be aware of the optimization. The presence of this optimization can, in some cases, change the observable behaviour of the program.

Solution 2 - C++

In your case , it will return a copy

If your code was

subline_t& subline(int, int)

then it would return a reference, which would yield in undefined behaviour.

Solution 3 - C++

Yes, for a function declared to return a struct, return of such a struct will copy it (though the compiler is empowered to optimize the copy away, essentially in cases where it can prove the optimization is semantically innocuous, you can reason "as if" the copying was guaranteed).

However, since you did tag this as C++, not C, why not supply your struct with a constructor, instead...? Seems clearer and more direct...!-)

Solution 4 - C++

yes , the return is a copy

subline_t subline(int x1, int x2, int id) {
        subline_t t = { x1, x2, id };
        return t;
}

If you put a referencer, then its not a copy

subline_t & subline(int x1, int x2, int id) {
        subline_t t = { x1, x2, id };
        return t; // will result in corruption because returning a reference
}

Solution 5 - C++

It will always return a copy.

If you want to avoid the performance hit of copying the object on return, you can declare a pointer, build an instance of the object using new, and return the pointer. In that case, the pointer will be copied, but the object won't be.

Solution 6 - C++

Returing objects in C++ done by value and not by reference.

> the reference to subline_t t goes out of scope

No, the object is copyed.

> will the return statement always copy

Yes and not... Semantically it behaves like copy, but there is something that is called return value optimization that saves copy constructor.

foo make_foo()
{
    foo f(1,2,3);
    return f;
}

foo ff=make_foo(); /// ff created as if it was created with ff(1,2,3) -- RVO
foo ff2;
ff2=make_foo(); /// instance of foo created and then copied to ff2 and then old
                /// instance destroyed

Solution 7 - C++

It returns a copy, which is what you want it to do. Changing it to return a reference will result in undefined behaviour in the assignment to line.

However, the idiomatic way to do this in C++ is with constructors and assignment lists. This encapsulates code and data structures better, and allows you to avoid the plethora of intermediate objects that compilers are free to construct/destruct/copy.

struct subline_t {
        int x1;/*top*/
        int x2;/*bottom*/
        int id;

// constructor which initialises values with assignment list.
  subline_t(int the_x1, int the_x2, int the_id) :
    x1(the_x1),
    x2(the_x2),
    id(the_id)
  {
  }
};


int main(){
    subline_t line2(0,0,0); // never requires a copy or assignment.
}

Solution 8 - C++

The returned class or struct may or may not be copied, depending if the compiler uses copy elision. See the answers to What are copy elision and return value optimization? In short, whether it is copied or not depends on a number of things.

You can of course avoid a copy by returning a reference. In the case of your example, returning a reference is invalid (though the compiler will allow it) because the local struct is allocated on the stack, and therefor the returned reference refers to a deallocated object. However, if the object was passed to your function (directly or as a member of an object) you can safely return a reference to it and avoid copy-on-return.

Finally, if you cannot trust copy elision and you want to avoid copies, you can use and return a unique_ptr instead of a reference. The object itself will not be copied, although the unique_ptr itself may or may not be (again, depending on copy elision!). Copying/moving a unique_ptr is however very cheap if copy elision of the unique_ptr does not happen for some reason.

Here is an example using unique_ptr:

#include <memory>

struct A {
public:
  int x;
  int y;

  A(int x, int y) : x(x), y(y) {
  }
};

std::unique_ptr<A> returnsA() {
  return std::make_unique<A>(3, 4);
}

int main() {
  auto a = returnsA();
}

Note that you must (unfortunately) declare a constructor for your struct, or else make_unique will not compile due to inadequacies of C++.

Solution 9 - C++

For the structure subline_t you've defined, yes, it will always return a copy.

Solution 10 - C++

Just FYI, since in this case you are using only a struct(ure), it is the same behavior as in C language.

Though this is a language feature, it is recommended that it shall not be used

Solution 11 - C++

I do not agree and NOT RECOMMEND to return vector to change values: Is much faster pass as reference:

void vectorial(vector <double> a, vector <double> b, vector <double> &c)
{
	c[0] = a[1] * b[2] - b[1] * a[2]; c[1] = -a[0] * b[2] + b[0] * a[2]; c[2] = a[0] * b[1] - b[0] * a[1];
}
//This is slow!!!:
vector <double> vectorial(vector <double> a, vector <double> b)
{
	vector <double> c{ a[1] * b[2] - b[1] * a[2], -a[0] * b[2] + b[0] * a[2], a[0] * b[1] - b[0] * a[1] };
	return c;
}

I tested on VS2015 with following results in release mode:

By reference:8.01 MOPs and returning vector: 5.09 MOPs 60% worse!

In debug mode things are much worse:

By reference:0.053 MOPS and return vector: 0.034 MOPs

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionldogView Question on Stackoverflow
Solution 1 - C++Greg HewgillView Answer on Stackoverflow
Solution 2 - C++TomView Answer on Stackoverflow
Solution 3 - C++Alex MartelliView Answer on Stackoverflow
Solution 4 - C++Andrew KeithView Answer on Stackoverflow
Solution 5 - C++csjView Answer on Stackoverflow
Solution 6 - C++ArtyomView Answer on Stackoverflow
Solution 7 - C++RoddyView Answer on Stackoverflow
Solution 8 - C++Alex K.View Answer on Stackoverflow
Solution 9 - C++JacobView Answer on Stackoverflow
Solution 10 - C++AlphaneoView Answer on Stackoverflow
Solution 11 - C++mathengineerView Answer on Stackoverflow