References in C++

References in C++

innocentzero

2026-06-15

#cpp | Status: Complete

A bit on how references and ownerships work in C++. Truth be told, they don't.

References in C++

C++11 introduced 5 types of objects; lvalues, rvalues, glvalues, prvalues, xvalues.

int x = 5;
//here x is an lvalue and 5 is a prvalue

It means that the contents can now be safely renamed to something else because the previous name will soon not be valid.

int b(int x){
    int y = x*x;
    return y;
    //over here y is an lvalue that is soon going to go out of scope. So internally, its memory need not be copied. Internally the value that is binding to the return value can simply be optimised to refer to the original memory since it is the sole owner of the memory.
}

int main(){
    int z = 0;
    int k = b(z);
    //over here, k will simply start pointing to the original memory owned by y inside the function b; we say that the resource has moved from y inside the function to k outside the function.
}

An rvalue's resources can be moved safely.

lvalue references

An lvalue reference can be thought of as an alias to the variable, an alternate name.

int x = 5;
int &y = x;

cout << (&y == &x ? "true": "false") << '\n';
//returns true because both the values point to the same location

y = 6;
cout << x << '\n';
// will print 6;

Lvalues reference can't bind to an rvalue or a const-lvalue. A reference to a const lvalue, however, can.

int &x = 5; //error
const int &x = 5; //ok, but x cannot be modified
const int v= 2;
const int &l = v; //ok, but l cannot be modified

Pass by reference in functions

Take the function void sqr(int x). Suppose it does

void sqr(int x){
    x = x*x;
}

For very obvious reasons it won't work. The assignment is in local scope, and the variable is copied into the scope of the function before anything else is done.

In C, we solved this problem using pointers. In C++, we can instead pass the reference to x.

void sqr(int &x){
    x = x*x;
}

Now the function will work as expected.

Return by reference and Dangling references

When the object being referenced to is destroyed before its reference, it is called a dangling reference.

Suppose the function signature is this:

int & ret(int &x){
    int y = x; // copy of x being formed
    return y;
}

This is clearly problematic. By the time the function's return binds to something, the object it is referring to is already destroyed. This is an example of a dangling reference. This is also true for prvalues.

If however, the return type was a const int& and the variable being returned was static, then it will work.

const int & ret (int &x){
    const static int y = x; // static copy formed
    return y; // ok, object exists till the end of the program lifetime
}

This happens because a static object is created at the beginning of the program and stays in memory till the end of the program.

It would work, in theory, to bind a const reference to a non-const static variable. However, the results can be unpredictable so it isn't advised.

Eg.

const int & fun(){
    static int y = 0;
    y++;
    return y;
}

int main(){
    const int& id = fun();
    const int& id1 = fun();
    cout << id << id1 << '\n'; // prints 22 instead of the expected 12
}

Instead, we can bind it with a regular variable so that a copy is made.

It is perfectly ok to return a reference to a pass-by-reference parameter, since the object will continue to exist even after the function scope ends.