When you return an object by reference (i.e. T& fun(...) { ...}
) then you are returning the same object that you were using inside your function, while when you return the object by value (i.e. T fun(...) { ...}
) the object is copied before returning the function.
You can check this if you print your object's memory address inside the function and after it has been returned:
printf("%p\n", &my_object);
The const
only says that the compiler should make sure you are not modifying the object from the outside (i.e. you cannot do: object.field = value
).
I have arranged this sample that shows all the differences between those approches:
#include <stdio.h>
class X {
public:
int i;
X();
X(const X&);
};
// Copy constructor
X::X(const X& x) {
printf("Copy constructor invoked\n");
}
// Default constructor
X::X() : i(0) {
printf("Creating a object\n");
}
X my_fun_1(X& x) { return x; }
X& my_fun_2(X& x) { return x; }
const X& my_fun_3(X& x) { return x; }
int main () {
X x0;
printf("\nInvoke my_fun_1\n");
X x1 = my_fun_1(x0);
printf("\nInvoke my_fun_2\n");
X& x2 = my_fun_2(x0);
printf("\nInvoke my_fun_3\n");
const X& x3 = my_fun_3(x0);
printf("\nResults:\n");
printf("x0 => %p\n", &x0);
printf("x1 => %p\n", &x1);
printf("x2 => %p\n", &x2);
printf("x3 => %p\n", &x3);
x0.i = 1;
x1.i = 1;
x2.i = 1;
//Compile-time error: x3.i = 1;
return 0;
}
Compile and run it, the output should be:
$ g++ a.cpp && ./a.out
Creating a object
Invoke my_fun_1
Copy constructor invoked
Invoke my_fun_2
Invoke my_fun_3
Results:
x0 => 0x7fff8710cce0
x1 => 0x7fff8710ccf0
x2 => 0x7fff8710cce0
x3 => 0x7fff8710cce0
Notice:
- If you don't use
&
then the copy constructor is used
- If you use
const
then modifying the returned object using that reference is a compile-time error.