This post is part of a series of tutorials on C++
In C++, some care must be taken if one wants to pass around objects as parameters and return types to functions. The default method for passing a parameter to a function is to pass-by-value. As a result, even a simple function call such as
In actuality requests that one makes a copy of some parameter whenever
foo() is called. For primitive data types, this is handy because it prevents you from accidentally changing a value when it is out of scope. For example:
Protects the validity of the variable
bar being passed into the function
foo(). The expense is that a copy of
bar must be made when
param is created. But, for a primitive type, this is (maybe) not so expensive, unless
foo() is called repeatedly. When using an object, this could add up, particularly when the object has a large number of data members that all need to be copied.
To get around this, we can take advantage of references, which when passed into functions do not make a copy but instead allow you to refer to the same address in memory without requiring the copy. Of course, this could be particularly disributive:
The compound multiple-and-assignment stores the produce of
param*2 back into
param, which is really just another name for whatever variable we were already working with. Thus:
Languages like Java make the default behavior that everything is passed by reference and that copies need to be explicit. This, of course, creates the above problem for the unwary. In C++, one can fix this by being explicit on whether or not the reference should be treated as read-only, using
Even though the above is a little bit more cumbersome, it also forces the programmer to think carefully about how variables are used internally. Am I just reading the value, or do I want to update it too? If you’re just reading, you are forced to code
foo() differently. For example:
Which is likely what we intended for
foo() in the first place. Getting comfortable with const references will save you a lot of grief. It will also force you to think carefully about as to if your member functions (and, in particular, operators that you overload) are read-only or if they are meant to change parameters too.
And, for complex types, this distinction becomes even more important. Using references helps with memory usage (e.g., preventing unnecessary copying), but it also helps prevent you from accidentally modifying member types. For example:
As we’ll see in many of the upcoming tutorials, we’ll be using const references and references to pass around types. For C++ objects, there is rarely a good reason to pass an instance of a class by value, so as a rule of thumb if you ever see yourself accidentally doing it, you may have intended to use a const reference instead!