tags:

views:

589

answers:

9

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?

+2  A: 

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.

Tom
Returning a reference is not undefined behavior in and of itself. Returning a reference to a local is, but returning a reference to global, static, field of `this`, or heap-allocated object is perfectly fine.
Pavel Minaev
Careful with heap-allocated objects though - the caller probably won't expect to be responsible for deleting that object if you return a reference.
Steve314
@Steve314: Pavel didn't say the caller was responsible for freeing it, he said it was heap-allocated. Maybe someone else is responsible for freeing it, but the "subline" call returns a view of it. This could happen if for example "subline" was returning cached values. Obviously the caller would need to know the dynamic scope of the object (that is, how long it can be relied on to remain valid).
Steve Jessop
+9  A: 

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, related to this is 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.

Greg Hewgill
The link you present says that the standard allows the optimization, as long as it doesnt change the behaviour of the program: "In general, the C++ standard allows a compiler to perform any optimization, as long as the resulting executable exhibits the same observable behaviour as if all the requirements of the standard has been fulfilled"
Tom
If you've read further, you would have also seen that the linked article says afterwards: "The term return value optimization refers to a special clause in the C++ standard that allows an implementation to omit a copy operation resulting from a return statement, even if the copy constructor has side effects, something that is not permitted by the as-if rule in itself."
Pavel Minaev
@Greg - At first sight, you're suggesting returning a reference to a local variable - ie a dangling pointer. With POD, this particular program will work in practice, but...
Steve314
Greg Hewgill
You shouldn't return reference to temporary object.
Kirill V. Lyadvinsky
A: 

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

Jacob
+1  A: 

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...!-)

Alex Martelli
Why supply a `struct` with a copy constructor when it doesn't do anything different from what a default copy constructor does? Also, doing so would make it non-POD, which may be important elsewhere.
Pavel Minaev
if instead of a struct I used a class in C++, would it still copy?
ldog
I mean, if the code was identical with only syntatic changes of struct to class.
ldog
It still would. The only difference between `class` and `struct` is that `class` members and base classes are `private` by default, while `struct` members and base classes are `public` by default. Otherwise they work exactly the same.
Pavel Minaev
@Pavel, I did not say _copy_ constructor -- that `subline` function should just morph into a `subline_t` ctor, it's just handier!
Alex Martelli
I suspect the 'typedef struct' is a clue that very little C++ is happening here, if any.
Steve314
I "fixed" the `typedef struct`, but yes, the original was in that weird C/C++ language.
MSalters
+1  A: 

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
}
Andrew Keith
+2  A: 

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.

csj
It might still be often wiser to rely on return value optimization. I think GCC does that even with -O0 and you'll need to use the -fno-elide-constructors switch if you want the copying to happen.
UncleBens
A: 

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

Alphaneo
What is a language feature in question, and why is it recommended that it shouldn't be used?
Pavel Minaev
@Pavel, this is a nice question. It is because, we would be copying the data twice. Once during setting the structure inside the routine, and once during copying the return data.
Alphaneo
@Alphaneo, please read on RVO...
Pavel Minaev
Also on premature optimisation. Code to share resources in order to "avoid a copy" may well be slower than just copying a tiny struct like this
Steve Jessop
A: 

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
Artyom
Good, but there's no guarantee that RVO will kick in. The compiler still has freedom to copy, and it _must_ check for a presence of a valid copy constructor even if it chooses to elide the copy.
Pavel Minaev
A: 

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.
}
Roddy