Зміст курсу
C++ Smart Pointers
C++ Smart Pointers
References Use Cases
References are like the unsung heroes of C++. They provide an alias to existing objects, which helps power various advanced use cases, while ensuring code clarity. To truly master memory management, it’s important to learn and respect references as much as smart pointers.
Avoiding unnecessary copying for function parameters
References are most commonly used for optimizing function parameters. When you pass an argument by reference to a function, you avoid the overhead of unnecessary copying. This is particularly useful when handling large objects. When done throughout your program, passing arguments by reference can lead to a substantial memory and performance optimization.
In this example, we're concatenating two strings without incurring the cost of creating their copies. Instead, we are using references to work directly with the original objects, and returning a new concatenated string from the function. The function can be called as follows:
Returning multiple values
References enable functions to return multiple values. While C++ functions usually return a single value, using references allows functions to modify the reference parameters as a means to return multiple values to the caller. Consider the following example for more clarity:
main
#include <vector> // function that returns the minimum and maximum values of a vector of integers // both the minimum and maximum values will be returned via references // boolean flag will also be returned from the function body bool findMinMax(const std::vector<int>& numbers, int& min, int& max) { if (numbers.empty()) return false; // no values to find // initializing min and max with the first element of the vector min = max = numbers[0]; // the following for loop calculates the minimum and maximum values for (int num : numbers) { if (num < min) min = num; // update min if num is smaller if (num > max) max = num; // update max if num is larger } // at this stage, the min and max reference variables will hold relevant values for the caller return true; // indicating successful calculation of min and max }
In the above code, we are using the power of references to return both the minimum and maximum values of a vector to the caller. After the function returns, the caller will find that the two reference variables contain the correct minimum and maximum values respectively.
Null safety
References offer a degree of null safety not found in pointers. Unlike pointers, references cannot be set to null. This means that when you declare a reference, it must be initialized with a valid value, and it cannot later be explicitly set to Null
either. For example, the following code is not allowed:
However, there’s an important caveat to remember. Even though references can’t be explicitly set to null, they can still “become null” in practice. This may happen when you inadvertently create a reference to an object that has been deleted or gone out of scope. Consider this code snippet:
main
#include <iostream> int main() { int* ptr = new int(42); // dynamically allocate an integer int& ref = *ptr; // create a reference to the allocated integer delete ptr; // deallocate the memory // at this point, ref has become a null reference because the object it referred to has been deleted. // accessing ref now would result in undefined behavior. // this line may cause a runtime error. std::cout << "Value through ref: " << ref << std::endl; }
In the above code, we have safely created a reference to a dynamic integer. Later that integer gets deallocated when we call the delete operator on the pointer. This causes the reference to become null.
Pointers vs references
Pointers and references are both powerful tools in C++ with specific use cases. As a resourceful C++ programmer, it’s important to know when to use each.
-
Use pointers when you want to point to different objects, or when you want to represent the absence of an object with null. Pointers are versatile and offer more flexibility in managing dynamic memory.
-
References are typically used in scenarios where you want to directly work with existing objects, without doing any copying or reassignment. As mentioned in the above headings, use references when you need to pass arguments to functions without the overhead of copying, return multiple values from functions, or when you want null safety.
We will delve deeper into the differences between pointers and references in a later section.
Дякуємо за ваш відгук!