References In C++ | Declare, Types, Properties & More (+Examples)
Most of you must have at least two names, one that your loved ones at home use and one that you use outside of your homes. While they are two different names, they are both used to recognize you. In this sense, they are your aliases. A reference in C++ programming language (and many other languages) fulfils the same role.
They are a way to create aliases or alternative names for existing variables. These names may be more descriptive, shorter versions, or a name that better meets your requirements. The use of references in C++ programs can improve code readability, facilitate efficient parameter passing, and avoid unnecessary object copying. In this article, we will explore the concept of references, their usage, applications, and the benefits they bring to C++ programming.
How To Create References In C++?
As discussed, a reference in C++ is an alias (alternative name) for existing variables. In other words, once a reference is initialized, it becomes another name for the same variable/ object.
- For example, say you have an integer variable named student_name, and you create a reference to this variable called st_nm.
- We use the address-of operator or the ampersand sign (&) to declare a reference in C++.
- Then, the reference will point to the memory address (or location in memory) of the student_name variable.
- You can use either the original variable name or the reference to access the data stored in this variable.
But this sounds just like pointers, right? Well, it is not.
Unlike pointers, references cannot be reassigned to refer to a different object after initialization. References provide a level of indirection and allow direct access to the object they refer to, eliminating the need for explicit dereferencing. Let's look at the syntax for the creation of references in C++, followed by an example to better understand this concept.
Syntax For References In C++:
Data_type reference_name =&existing_variable;
Here,
- The existing_name and reference_name refer to the original name of the variable and its reference/ alias name, respectively.
- The ampersand symbol (&) is the address-of operator that we use to assign the address of one variable to another.
Example:
int x = 5;
int& ref = x;
Here, the ref variable is a reference to x. Any modifications to ref will also have an impact on x, and vice versa. Below is a sample C++ program that illustrates how you can create a reference of a variable.
Code Example:
Output:
a = 5
a = 6
Explanation:
In the C++ program above, we first include the header file <iostream> for input-output operations and use the standard namespace.
- We then define a function increment(), which takes the reference to variable num as a parameter.
- Inside the function, we use the increment operator to increase the value of the num variable by 1.
- Inside the main() function, we declare an integer variable a and initialize it with the value 5 using the assignment operator. We print the value of the variable using the count command.
- Then, we call the increment() function passing variable as the argument.
- Since we have supplied the value of a by reference, any modifications made to the variable's value inside the function will modify the initial/ original value.
- Next, we use the cout command to print the modified value of a to the console. The output shows that the value was incremented by 1.
Types Of Reference Variables In C++
There are primary 5 types of references in C++. We will discuss each of these with the help of examples in this section.
Lvalue References(&) In C++
Lvalue references are employed to denote entities that already exist in the memory. They can only bind to lvalues, which are variables with a persistent memory address and are specified with the ampersand symbol (&). Lvalue references are utilized for functions that need to change an object's value or access its members.
Code Example:
Output:
x before increment: 5
x after increment: 6
Explanation:
In the C++ example-
- We define a function called increment() that accepts the lvalue reference to an integer data type variable (int&) as a parameter. The function increases the integer's value by 1.
- Then, we declare the integer variable x and set its initial value to 5 in the main function.
- Next, we call the increment() function with x as an argument, changing x's value to 6.
- Finally, we use the cout command to print the x value both before and after the increment.
Rvalue References(&&) In C++
The Rvalue references in C++ refer to an object that is about to be destroyed or does not have a persistent memory address. They can only bind to Rvalues and are declared using the double ampersand symbol (&&). Instead of copying an object's value, Rvalue references can be used to relocate it.
Code Example:
Output:
Hello, world!
Explanation:
In the example, we also include the string library <string> besides <iostream> and namespace since we will be using string functions.
- We define a function concatenate(), which takes two rvalue references to string objects as argument and returns a string value.
- The function uses the concatenation/ addition operator to concatenate/ join two strings and returns the string.
- Inside the main() function, we initialize two string variables str1 and str2 with the values 'Hello' and 'world!', respectively.
- We then call the concatenate() function inside the cout command, passing the strings as arguments.
- For this, we convert the string variables into Rvalues using the move() function.
- The cout command thus prints the concatenated string as mentioned in the code comment.
Dangling References In C++
An object that has been eradicated or is presently outside the scope of the program is denominated as a 'dangling reference.' Commonly, in C++ programs, inaccurate outcomes result from the usage of such aforementioned dangling references.
Code Example:
Output:
| ^
main.cpp:4:9: note: declared here
4 | int x = 5;
| ^
Explanation:
- We define a function get_value(), which returns a reference to the local variable x.
- Inside this function, we initialize an integer variable x with value 5 and then return a reference to this variable.
- In the main() function, we call the get_value() function and assign the outcome to the reference variable y.
- This reference variable now points to an invalid or dangling memory address because once the function completes, x exits its scope, and its memory is deallocated.
- The undefined behavior results when we try to access y using the cout command. This could cause a crash, unexpected output, or other unknown behavior.
Note: The behavior of the program's reaction is ambiguous, and the outcome is indeterminate. A dangling reference could cause the program to crash or result in any other unexpected output when we attempt to access it.
Forwarding References In C++
Forward references (or forward declarations) are declarations or templates in C++ that introduce a type name without defining it. It is useful when you want to create a class or function that utilizes a particular type despite the said type being unspecified at the time.
Code Example:
Output:
42
hello
world
Explanation:
In this example-
- The function template my_print() uses a forwarding reference and only accepts one argument.
- This eliminates the need for extra copies or overloads and enables the function to accept any type of argument, including lvalues, rvalues, and const references.
- The forwarded value is simply printed using the function's std::forward<T>(value).
- We make three calls to my_print with various sorts of parameters in main().
- The output demonstrates that the values are reported accurately in each scenario.
Const References In C++
In C++, a const reference serves as a reference that is bound to either an object that is constant or some temporary object. In doing so, it restricts any adjustments to be made on the referred object via the said reference.
Code Example:
Output:
The value is 42
Explanation:
In this example C++ code-
- We define a function my_function() that takes a constant reference to an integer (const int&) as a parameter.
- This means that any attempt to alter the value of the variable passed as an argument (by reference) will result in an error during compilation. Therefore, such modification would be rendered infeasible.
- In the main() function, we declare and initialize an integer variable x with value 42.
- Then, we attempt to print the reference's value by calling my_function(). The output demonstrates that the value was printed accurately.
Note: Constant references can be helpful for avoiding extra copies of huge objects while still helping to prevent unintentional object modification.
Properties Of References In C++
References in C++ have the following properties:
- Creating Aliases: References provide an alias or an alternative name for an existing object. Once a reference is initialized, it becomes another name for the same object, and any modifications made through the reference affect the original object.
- No Memory Allocation: Unlike pointers, references do not allocate any memory. They simply provide a way to access and manipulate an existing object. When declaring a reference, it must be initialized with an object, and it cannot be reassigned to refer to a different object.
- Automatic Dereferencing: When using a reference, you do not need to explicitly dereference it, unlike pointers. You can directly use the reference variable as if you were accessing the original object.
- Reference Cannot be Null: References must always be initialized and cannot be null. You must bind a reference to an object at the time of declaration, and it cannot be left uninitialized.
- Reference Cannot Change Object: Once a reference is initialized to refer to an object, it cannot be changed to refer to a different object. References are constant in the sense that they always refer to the same object throughout their lifetime.
- Function Parameter Passing: References are often used as function parameters to pass arguments by reference. This allows functions to modify the original objects rather than creating copies.
- No Size Difference: References have the same size as the object they refer to. They do not add any overhead in terms of memory consumption.
Applications For References In C++
There are multiple applications of references in C++ programming, and we have discussed some of the most important ones in this section.
1. Modify the Passed Parameters in a Function
A function can modify a variable's value but with the condition that it receives a reference to said variable. References in C++ have the capability to transmit variables to functions using a reference to the address of the normal variable.
If a function receives a variable reference as an argument, it can alter its original value without creating fresh duplicates. This can be especially helpful when you need to alter the arguments' values.
Code Example:
Output:
Before swap: a = 5, b = 10
After swap: a = 10, b = 5
Explanation:
- In this example C++ program, we define a swap() function, which takes references to two integer variables, x and y, as parameters.
- It swaps the values stored in these variables using the temporary variable approach.
- Inside the main() function, we declare and initialize two variables, a and b, with values 5 and 10, respectively. We print these values using the cout command.
- Then, we call the swap() function, passing a and b as arguments.
- We print the values of a and b once more after invoking the swap function to ensure the values have been switched.
Note- We avoid making duplicates of a and b by giving pointers to them to the swap function, which allows us to change their values immediately inside the function. This can be more effective when working with huge objects than sending the variables by value.
2. Avoiding Creating a Copy of Large Structures
Using references in C++ to pass arguments to a function is more effective for huge structures, as it eliminates the overhead due to copying a complete object. This can be particularly crucial when working with huge data structures or expensive-to-copy items. We can alter the original object directly using references rather than by making a clone, which can save both time and memory.
Code Example:
Output:
Before modification: 0
After modification: 42
Explanation:
In C++ code-
- We define a structure LargeStruct using the struct keyword, which contains a large array named data with 10000 elements.
- Then, we define a function modifyStruct(), which accepts a reference to a LargeStruct object as a parameter and modifies the first element of the array.
- In the main() function, we declare an object of type LargeStruct called myStruct and then use a for loop to initialise its array elements.
- Next, we use the cout command to print the first element of myStrcut before modification.
- Then, we call the modifyStrcut() function, which modifies the first element. To demonstrate that myStruct has been updated, we again print the first element's value using the cout command.
- Note that the object myStruct was supplied to modifyStruct() via reference, allowing for immediate modification of the original object without duplicating the entire structure.
3. For Each Loop to Avoid the Copy of Objects
We generally use the for-each loop to iterate over containers like vectors. It is more effective to use a C++ reference to the individual items rather than copying them while iterating across a big vector. A reference variable can be used to accomplish this in the for-each loop.
Code Example:
Output:
42
42
42
42
42
Explanation:
In this example-
- We generate a vector of 5 LargeObjects by defining a LargeObject structure that holds a sizable array of integers.
- The vector is given some initial values, and the first element of each LargeObject in the vector is changed using a for each loop and a reference.
- We avoid producing needless copies of the objects, which can be time-consuming and memory-intensive when the objects are huge, by using a reference to each LargeObject in the vector.
- We use another for each loop with a const reference to print the value of the first element of each LargeObject in the vector after we have modified the objects in the vector.
4. For Each Loop to Modify an Object
References in C++ can be used in a range-based for loop to modify all objects in a container. By using references, you can directly modify the original objects within the loop.
Code Example:
Output:
Before modification: 1 2 3 4 5
After modification: 2 4 6 8 10
Explanation:
In this example, we have the same std::vector<int> named numbers as before. We want to modify all the elements of the vector by doubling their values, but this time, we will use references in the range-based for loop.
- We first print the original values of the vector using a range-based for loop with the cout command.
- Inside the loop, each element of the vector is accessed and printed.
- Notice that we use a const auto& to avoid making unnecessary copies of the elements since we are only reading them.
- Next, we use another range-based for loop with auto& to obtain a reference to each element in the vector. Using a reference in C++, we can modify the original elements directly within the loop.
- After modifying the elements, we again use a range-based for loop with const auto& to print the updated values of the vector.
5. C++ Reference as Parameter in a Function
References in C++ can be used as parameters in function declarations to pass arguments by reference. When a reference is used as a function parameter, any changes made to the reference inside the function will affect the original argument passed to the function. This allows for efficient modification of the original object without creating copies.
Code Example:
Output:
Before increment: 5
After increment: 6
Explanation:
In this example-
- We define a function called increment() that takes an int reference to the variable num as a parameter. The function increments the value of the num variable by 1.
- In the main() function, we declare an integer variable called value and assign it the value of 5.
- We then use the std::cout command to print the value of the variable before any modification is made.
- Next, we call the increment() function and pass the value as an argument.
- Since we pass value by reference, any modifications made to num inside the increment function will affect the original value variable.
- After returning from the increment function, we output the value of the value variable again to see the updated value.
6. C++ Reference as Return Value in Function
References in C++ can also serve as return values in functions. A reference that a function returns also contains an implicit pointer to the object it references. This is beneficial if we wish to change the original object straight from the calling function.
Code Example:
Output:
x = 10, y = 30
Explanation:
- We define a function max(), which takes references to two integer variables, a and b, as parameters.
- The function uses an if-else statement to find the larger of the two input values and returns the reference to the larger value among them.
- In the main() function, we declare and initialize two integer variables, x, and y, with the values 10 and 20, respectively.
- After that, we call the max() function, supplying x and y as parameters, and set the resulting reference's value to 30.
- Finally, we use the cout command to print the values of x and y to the console.
This example shows how to use a reference as a function's return value in C++. It is possible to directly modify the object from the calling function by returning a reference to its original form. This method proves more effective in terms of memory usage while still allowing for efficient edits to be made.
Advantages Of References In C++
Some of the primary advantages of using references in C++ programming are as follows:
- Efficiency: When working with huge objects or arrays, passing by reference is more effective than passing by value. The mere act of passing by value involves the formation of a replica of the object, which, owing to its complex nature, results in significant use of both time and memory. Using references in C++ instead allows us to change the original object directly without making a copy, which can save memory and time.
- Modifying original object: As opposed to the act of passing a value, when a reference in C++ is conveyed into a function, said function manipulates the initial iteration of that variable. Variable changes done inside the function are reflected outside of it. It is possible for us to directly modify the source object from the function that invokes it, thus saving both time and memory.
- Unique identity: When working with things that are too huge to duplicate, references in C++ can be utilized to indicate a unique identity. By employing contextual semantics, we can use the original entity rather than generating replicas of it.
Limitations Of References In C++
There are some limitations to using references in C++. They are-
- References are never NULL. Pointers are frequently set to NULL to show that they are not pointing to any real objects.
- When declared, a reference in C++ needs to be initialized. With pointers, there is no such restriction.
- A reference in C++ cannot be reset or changed to reference a different object after it has been established. Pointers are frequently used for this.
- References in C++ have the same scope as the item they refer to. As a result, the reference is no longer valid and cannot be utilized if the object leaves its range.
Note: References in C++ cannot be used to create data structures like linked lists, tree, etc., due to the aforementioned restrictions.
References Vs. Pointers In C++
Both pointers and references in C++ provide indirect access to variables/ objects whose addresses they hold. However, they have some important differences in terms of syntax, behavior, and usage. Here are some key differences between references and pointers in C++:
-
Syntax and Declaration:
- References in C++ are declared using the ampersand symbol (&) and must be initialized at the time of declaration. Once initialized, they cannot be changed to refer to a different object.
- Pointers are declared using the asterisk sign (*)/ indirection operator and can be declared without initialization. They can be assigned to point to different objects throughout their lifetime.
-
Nullability:
- References in C++ must always refer to a valid object and cannot be null. They must be initialized with an existing object and cannot be left uninitialized.
- Pointers can be assigned a null value (i.e., Null Pointer/ nullptr) to indicate that they do not currently point to any valid object. Pointers can also be assigned to point to a valid object or can be uninitialized.
-
Memory Allocation:
- References in C++ do not allocate any memory. They are simply an alias or alternative name for an existing object.
- Pointers allocate memory to store the memory address of an object. They can be dynamically allocated using the new operator and need to be deallocated manually using the delete operator or the free() function to avoid memory leaks.
-
Dereferencing:
- References in C++ are automatically dereferenced. That is, you can directly access and modify the object without explicit dereferencing when using a reference.
- Pointers need to be explicitly dereferenced using the dereferencing operator (*) to access or modify the object they point to.
-
Reassignment:
- References in C++ cannot be reassigned to refer to a different object after initialization. Once a reference is initialized, it remains bound to the same object throughout its lifetime.
- Pointers can be reassigned to point to different objects at any time.
-
Function Parameters:
- References in C++ can be used as function parameters to pass arguments by reference. Any modifications made to the reference parameter inside the function will affect the original argument.
- Pointers can also be used as function parameters to pass arguments by pointer. But by passing a pointer, the function can modify the pointed object or access its address.
-
Pointer Arithmetic:
- References in C++ do not support pointer arithmetic since they are not actual memory addresses.
- Pointers support pointer arithmetic, allowing you to perform arithmetic operations on pointers, such as incrementing or decrementing the memory address they point to.
Conclusion
References in C++ are used to create alias names/ alternative names for already-existent objects or variables. They provide access to the address of the other variables that they reference. C++ reference is the most straightforward and effective resource when no pointer notion exists in any other programming language. It can quickly obtain the original data at the appropriate location. The variable's initial location will be changed automatically if you make any modifications at any specific moment.
Also Read: 51 C++ Interview Questions For Freshers & Experienced (With Answers)
Frequently Asked Questions
Q. What is a reference in C++?
A reference in C++ is a variable that acts as an alias name for an existing variable. They hold the same memory location as the original variable and do not take up additional space. In other words, it stands for the name of another variable, location, or value and is declared using the ampersand symbol/ address-fo operator (&). A reference cannot be changed to refer to a different object once it has been initialized.
Q. How do you declare a reference in C++?
To declare a reference in C++, we use the ampersand symbol (&) in the declaration.
Syntax:
Data_type Variable_name =&existing_variable;
For Example:
int x = 5;
int& ref = x;
Here, the ref is a reference to x. Any modifications to ref will also have an impact on x, and vice versa.
Q. Can a reference be null in C++?
No, a reference in C++ cannot be null. References must always refer to an existent object because they can never be null.
Q. Can you create an array of references in C++?
No, you cannot make an array of references in C++. This is because references cannot be kept in an array because they are not objects and do not have a size. The dimensions of references are influenced by the type of entity they refer to, whereas arrays necessitate that all elements share identical dimensions.
Q. How do you pass arguments by reference in a C++ function?
By utilizing the & symbol in the function parameter declaration, arguments can be provided by reference to a function in C++. In instances where a reference is utilized as an implementation input for a function, it should be noted that the function will operate on the original said program variable rather than initiating a pass-by-value occurrence.
Code Example:
Output:
Before swap: x = 10, y = 20
After swap: x = 20, y = 10
Explanation:
In this program, we define the function swap, which swaps the values of two integer references given as parameters. Declared within the main function are a pair of integer variables named x and y. As they are initially assigned values upon declaration, both have been set to 10 and 20, respectively. The swap function is then called with the inputs x and y. We then print the x and y values.
Q. Can you change the reference of a C++ reference variable?
No, you cannot change the reference of a C++ reference variable. Once a reference is initialized to an object, it cannot be changed to refer to another object.
Q. Can a C++ reference refer to a const variable?
Yes, a C++ reference can refer to a const variable. A reference that is const in nature refers to an object which has been bounded by a const object and henceforth cannot undergo alterations even if mediated via the same reference.
Q. How are references different from pointers in C++?
References and pointers may seem the same in C++, but they are not. Some differences are:
- The pointer variable contains n levels of indirection, including single, double, and triple levels. However, the reference variable in C++ has just one degree of indirection.
- No changes can be made to reference variables once they have been assigned, unlike a pointer, which can be reassigned to point to the address of another variable.
- The reference initialization must happen along with the declaration. That is, a reference in C++ can never be declared null, whereas a pointer can.
You might also be interested in reading the following:
- Do-While Loop In C++ | Introduction, Syntax, & More! (+Examples)
- Switch Case In C++ (Statement), Uses, Break & More With Examples
- Logical Operators In C++ | Use, Precedence & More (With Examples)
- Bitwise Operators In C++ Explained In Detail With Examples
- C++ Type Conversion & Type Casting Demystified (With Examples)
Login to continue reading
And access exclusive content, personalized recommendations, and career-boosting opportunities.
Comments
Add comment