#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?
To expand on @flyfishr64's answer
The copy constructor is invoked here because this:
is an initialization. You are using fun() to construct the object, not invoking the default constructor. It is equivalent to:
The "Cons" you see printed out is for the instance in fun(). See this article: Assignment operator in C++ for more.
In this code:
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
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 thethis
pointer, so it doesn't matter that it's no longer valid.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
When you change that to:
You are now returning a copy. If the compiler is clever enough it might do:
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 structureX
and after return fromfun()
call another method that internally allocates some memory on stack (this should overwrite the original memory used byX
infun
) and stores some values on stack (preferable 0's). After this second method returns try to print out values from theX
using the original reference returned fromfun
...