Reputation: 3038
My understanding of references is that they are an alias to an already-existing variable - they cannot be null. They are useful for function calls when modifying the original inputs, as references are considered safer than pointers.
Besides the above, and cases where references are mandatory, are there other reasons/use cases to use references as opposed to already-existing variables that the references point to?
Edit: Note that I said Besides the above. Meaning I want to know when else references are useful - when not required - outside of calling functions (I already know that). I also specifically want to know when references are preferred over the original variables, not over pointers (I already learnt from another question to "use references when you can, pointers when you must" when it comes to choosing between the two).
Upvotes: 7
Views: 3705
Reputation: 613
We use Reference because of the following things
To modify local variables of the caller function.
For passing large sized arguments.
To avoid Object Slicing.
To achieve Run Time Polymorphism in a function.
For more info, see http://www.geeksforgeeks.org/when-do-we-pass-arguments-by-reference-or-pointer/
Upvotes: 4
Reputation: 40645
It is a common misconception that references are safer than pointers, yet it is a misconception. It is just as easy to generate null-references and other illegal references. And these can propagate quite far before blowing up your program. Here are some examples:
Creation of null-references: Just dereference a null-pointer to pass the result to something that expects a reference.
class Foo {
public:
Foo() : bar(null_ptr) {}
void setSize(size_t newSize) {
delete bar;
bar = new int[newSize];
}
doSomething() {
myVec.push_back(bar[0]); //This will blow up somewhere in the push_back() implementation, not here!
}
private:
int* bar;
std::vector<int> myVec;
};
void baz() {
Foo myFoo;
myFoo.doSomething();
}
The point is that the code above won't blow up at the point where you dereference the null-pointer, it will just silently create a null-reference. That is legal, because dereferencing a null-pointer is defined to be undefined behavior, and creating a null-reference is a valid thing for the compiler to do.
The null-reference will be successfully passed to std::vector<>::push_back()
, which will segfault only when it itself tries to use the reference to actually get to the value behind it.
Dangling references: Just let the referenced object end its lifetime before the reference does. Again, just the same problem as with pointers:
std::vector<int> foo;
foo->push_back(7);
int& bar = foo[0]; //perfectly legal
bar *= 6; //perfectly legal
foo->push_back(8); //perfectly legal
cout << "The answer is: " << bar; //BOOM, bar is dangling, undefined behavior results
Note: This code may actually run as expected, just like code accessing a dangling pointer may reproducably run as expected.
Out-of-range references: Just as easily done as with pointers:
std::vector<int> array;
array.resize(7);
int& bar = array[7]; //undefined behavior, even if the compiler detects this, it will silently ignore it
bar = 42; //since this is undefined behavior, the compiler may optimize away this line
As with the dangling reference, this code may run perfectly fine, but it may not do what you think it does. Due to optimization, it may not even write to the out of range element. Or it may corrupt the heap, or the stack, or both, or silently compute wrong results. Just blowing up with a segfault is actually the most unlikely outcome here.
As you see, the last two example codes don't even require an explicit pointer anywhere, they use only the modern, shiny C++ style data structures. Yet they result in undefined behavior that will not strike at the place where it is invoked. The illegal reference may be propagated any distance from the place where it was created before noticeably bad things start to happen. Which is precisely why people dread using pointers; the danger from pointers and references is the same.
So, really, use references where it makes sense to you. But do not rely on them being "safe".
Upvotes: 1
Reputation: 409356
Lets say you have a large structure, or a std::vector
or a std::string
object, and you pass that by value to a function. That means that the object is copied which might be quite inefficient for large object (like say a vector of a couple of million entries). Then you can use a reference to a constant object like e.g. std::vector<SomeType> const& my_object
.
Upvotes: 6
Reputation: 1952
Use references where you can instead of pointers. Unless you want to manipulate low level memory you should not be dealing with pointers. Another usage would be keeping the main data on heap using new as a pointer and passing a reference of that pointer. But with new unique_ptr, shared_ptr and weak_ptr combination even that is not needed. The only place where a pointer is needed is when your object can be nullptr because references cannot be NULL. You can safely assume that a reference is a valid object unless someone has twisted the code in a perverse way.
Upvotes: 0