views:

293

answers:

4
#include <iostream>
using namespace std;

class X {
        public:
                X() {
                        cout<<"Cons"<<endl;
                }
                X(const X& x){
                        cout<<"Copy"<<endl;
                }
                void operator=(const X& x){
                        cout<<"Assignment called";
                }
};

X& fun() {
        X s;
        return s;
}

int main(){
        X s = fun();
        return 0;
}

This code calls the copy constructor also. Why does this work? I recall that the first time I ran this program, it seg faulted. But after a while, it started calling this copy cons. and now works!! Wierd.

But if I replace, fun() as follows:

X fun() {
        X s;
        return s;
}

Then copy cons. is not called. I thought that the copy cons. would be called in this case. But as pointed out by @flyfishr64, RVO is coming into play here. But it still does not explain the case where I am returning a reference. I think it should always segfault.

Any explanations?

+2  A: 

In this code:

X fun() {
        X s;
        return s;
}

the copy constructor isn't getting called because of the Return Value Optimization which allows the compiler to bypass creating the local variable 's' and construct X directly in the returned variable.

You can read more about RVO here

Jeff Paquette
+1  A: 

To expand on @flyfishr64's answer

The copy constructor is invoked here because this:

X s = fun();

is an initialization. You are using fun() to construct the object, not invoking the default constructor. It is equivalent to:

X s(fun());

The "Cons" you see printed out is for the instance in fun(). See this article: Assignment operator in C++ for more.

Doug T.
+4  A: 

This returns reference to an object on stack which does not exist once the method returns - the stack is unwinded, the memory is still there but you should not be using it

X& fun() {
        X s;
        return s;
}

When you change that to:

X fun() {
        X s;
        return s;
}

You are now returning a copy. If the compiler is clever enough it might do:

X fun() {
    return X();
}

In that case the X is allocated directly in the callers stack so that copy is not required.

If it segfault or not depends on if you are accessing invalid memory.

In your example you don't access any values from the structure. To see segfault, first keep a reference that you returned with fun() add some variables into structure X and after return from fun() call another method that internally allocates some memory on stack (this should overwrite the original memory used by X in fun) and stores some values on stack (preferable 0's). After this second method returns try to print out values from the X using the original reference returned from fun ...

stefanB
A: 

When you return a reference to a local variable like that, you're invoking undefinied behaviour.

It happens to work in this case because none of the functions of class X actually use the this pointer, so it doesn't matter that it's no longer valid.

Joe Gauterin
Merely returning such a reference invokes UB? You have reference for that?
anon