According to Bjarne there are 3 types of references. Which are :
- lvalue references: refers to non-temporary object whose value can be changed.
- const references: refers to non-temporary object whose value cannot be changed.
- rvalue references: refers to temporary object whose value is not necessary after it has evaluated.
references
For a type T, a notation T& is used for lvalue references. General rule of lvalue is if you have a name for variable it is an lvalue. on the other hand, T&& is used for rvalue reference. General rule of rvalue is expression which is literal or expressions whose result is not set to any variable. following piece of code is the example of lvalues and rvalues.
#include <iostream>
using namespace std;
int main() {
string str = "hi";
string& str1 = str; // str1 is another name for str. and lvalue
cout << (str == str1) << endl; // true
string& wrong1 = "hi"; // compile error. hello is not modifiable
string&& wrong1 = "hi"; // OK
cout << wrong1 << endl;
return 1;
}
Lvalue reference usages.
an lvalue references play a big role in memory savings and improve readability of source code.
USAGE 1 : aliasing names.
sometimes we need to use an object which is stored in containers like vector.
for Example:
int main() {
.....
.....
std::cout << veryLongVectorName[expression that calculates the index].name << veryLongVectorName[expression that calculates the index].age << std::endl;
return 1;
}
this program is very ugly to read. so, we can do like following.
1: int main() {
.....
2: SomeObject someObject = veryLongVectorName[expression that calculates the index];
.....
2: SomeObject someObject = veryLongVectorName[expression that calculates the index];
3: std::cout << someObject.name << someObject.age << std::endl
4: return 1;
5:}
now it became easy to read(at least for me). But it has one problem which is inefficient use of memory.
expression at line 2 copies the object stored in vector to a new memory. So, if we code like following, we object will not be copied.
SomeObject& someObject = veryLongVectorName[expression that calculates the index];
Another very effective usage is in for each loops. The following loop is inefficient because it will copy every object to variable o.
for (auto o : veryLargeObjectVector) {
.....
}
if we use use "auto & o", objects will not be copied to a new memory but just referenced by o.
Lvalue references are used to avoid a copy of function return values too. For example
VeryBigObject& veryBigObject = find(arrayOfVeryBigObject);
To summarize briefly, lvalue references are used to avoid copying objects.
Function Parameter Passing.
in briefly there are 4 parameter passing ways.
1. call-by-value
2. call-by-lvalue-reference(it can cause side-effect)
3. call-by-lvalue-reference-to-a-constant (prevent side-effect)
4. call-by-rvalue-reference
I will omit explanation of first 3 parameter passing methods, since these are old methods and writing every detail makes me boring even I write this blog to improve my English (this is why my English is so poor).