A reference will ensure that no object is created when used as a parameter. This may have high implications if the object occupies a lot of memory, or it is slow to create.
Assume a C++ string composed of "Hello, this is me here. I'm a string made of a lot of characters and I do occupy a lot of space, although I'm somewhat quick to build". This string has 133 characters. Each character occupies 8 bits on most systems. 8 x 133 = 1,064 bits. Now.. look at the following:
Code:
std::string concatenate(std::string str, std::string extra) {
return str + extra;
}
int main() {
std::string foo = "Hello, this is me here. I'm a string made of \
a lot of characters and I do occupy a lot of space, \
although I'm somewhat quick to build.";
std::string bar = " I shouldn't really be passed by value";
std::cout << concatenate(foo, bar);
}
Lots of wasted memory. First in main I allocate 1,064 bits from the stack with foo plus 38 x 8 = 304 bits with bar.
Next I call concatenate(). Since I'm not passing by reference, two new string instances will be created and their copy constructors ran to initialize them. That's 1,064 + 304 bits on top of the previous ones. Inside the function I create a new string that is another 1,064 + 304 bits with that return statement. It's a temporary unnamed variable that is assigned the contents of both strings.
After the return statement, the destructors for std::string str and std::string extra are ran. And back in main, after the cout statement is evaluated, the destructor for the temporary unnamed std::string that is the return type of concatenate() is also ran.
If instead I pass both string as references, all the construction and destruction, plus extra memory use of str and extra are not performed.
Now... think of a more complex objects like an user-defined object occupying 4k which constructor needs to open a file 200k and search for a string, or even worst, a vector of 100 of such objects.
A reference will simply refer to the actual object and not create anything.