C++ References and const References

A reference is another name (an alias) for an existing variable. It is written with & in the declaration.

#include <iostream>

int main() {
    int a = 10;
    int& ref = a;               // ref is another name of a
    ref = 20;
    std::cout << a << ' ' << ref << ' ' << (&a == &ref) << '\n';
}
Output

20 20 1

Pass by reference

With a reference parameter, the function works on the original variable, with no copy.

#include <iostream>

void swap_values(int& x, int& y) {
    int temp = x;
    x = y;
    y = temp;
}

int main() {
    int a = 1, b = 2;
    swap_values(a, b);
    std::cout << a << ' ' << b << '\n';
}
Output

2 1

const reference: fast and safe

For big objects, pass by const T&. No copy is made, and the function can not change the object.

#include <iostream>
#include <string>
#include <vector>

void print_all(const std::vector<std::string>& names) {       // no copy, read only
    for (const auto& n : names) std::cout << n << ' ';
    std::cout << '\n';
}

int main() {
    std::vector<std::string> names = {"Riya", "Aman", "Meera"};
    print_all(names);
}
Output

Riya Aman Meera

#include <string>

void change(const std::string& s) {
    s += "!";                 // error: s is const
}

int main() { }
Output

Readonly.cpp: In function 'void change(const std::string&)':
Readonly.cpp:4:7: error: no match for 'operator+=' (operand types are 'const std::string' {aka 'const std::__cxx11::basic_string<char>'} and 'const char [2]')
4 | s += "!"; // error: s is const
| ~~^~~~~~
• there are 5 candidates
In file included from /usr/local/include/c++/16.2.0/string:58,
from Readonly.cpp:1:
• candidate 1: 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' (near match)
/usr/local/include/c++/16.2.0/bits/basic_string.h:1501:7:
1501 | operator+=(const basic_string& __str)
| ^~~~~~~~
• passing 'const std::string*' {aka 'const std::__cxx11::basic_string<char>*'} as 'this' argument discards qualifiers
• candidate 2: 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(const _CharT*) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' (near match)
/usr/local/include/c++/16.2.0/bits/basic_string.h:1511:7:
1511 | operator+=(const _CharT* __s)
| ^~~~~~~~
• passing 'const std::string*' {aka 'const std::__cxx11::basic_string<char>*'} as 'this' argument discards qualifiers
• candidate 3: 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(_CharT) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' (near match)
/usr/local/include/c++/16.2.0/bits/basic_string.h:1521:7:
1521 | operator+=(_CharT __c)
| ^~~~~~~~
• conversion of argument 1 would be ill-formed:
• error: invalid conversion from 'const char*' to 'char' [-fpermissive]
Readonly.cpp:4:10:
4 | s += "!"; // error: s is const
| ^~~
| |
| const char*
• candidate 4: 'template<class _Tp> constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_If_sv<_Tp, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
/usr/local/include/c++/16.2.0/bits/basic_string.h:1548:9:
1548 | operator+=(const _Tp& __svt)
| ^~~~~~~~
• template argument deduction/substitution failed:
In file included from /usr/local/include/c++/16.2.0/bits/char_traits.h:52,
from /usr/local/include/c++/16.2.0/string:45:
• /usr/local/include/c++/16.2.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using std::enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = std::__cxx11::basic_string<char>&]':
• required by substitution of 'template<class _CharT, class _Traits, class _Alloc> template<class _Tp, class _Res> using std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_If_sv = std::enable_if_t<((bool)std::__and_<std::is_convertible<const _Tp&, std::basic_string_view<_CharT, _Traits> >, std::__not_<std::is_convertible<const _Tp*, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>*> >, std::__not_<std::is_convertible<const _Tp&, const _CharT*> > >::value), _Res> [with _Tp = char [2]; _Res = std::__cxx11::basic_string<char>&; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
/usr/local/include/c++/16.2.0/bits/basic_string.h:159:8:
159 | using _If_sv = enable_if_t<
| ^~~~~~
• required by substitution of 'template<class _Tp> constexpr std::__cxx11::basic_string<char>::_If_sv<_Tp, std::__cxx11::basic_string<char>&> std::__cxx11::basic_string<char>::operator+=(const _Tp&) [with _Tp = char [2]]'
/usr/local/include/c++/16.2.0/bits/basic_string.h:1548:2:
1548 | operator+=(const _Tp& __svt)
| ^~~~~~~~
• required from here
Readonly.cpp:4:10:
4 | s += "!"; // error: s is const
| ^~~
• error: no type named 'type' in 'struct std::enable_if<false, std::__cxx11::basic_string<char>&>'
/usr/local/include/c++/16.2.0/type_traits:2946:11:
2946 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
| ^~~~~~~~~~~
• candidate 5: 'constexpr std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(std::initializer_list<_Tp>) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
/usr/local/include/c++/16.2.0/bits/basic_string.h:1535:7:
1535 | operator+=(initializer_list<_CharT> __l)
| ^~~~~~~~
• no known conversion for argument 1 from 'const char [2]' to 'std::initializer_list<char>'
/usr/local/include/c++/16.2.0/bits/basic_string.h:1535:43:
1535 | operator+=(initializer_list<_CharT> __l)
| ~~~~~~~~~~~~~~~~~~~~~~~~~^~~

References vs pointers

PointReferencePointer
Must be initializedYesNo
Can be nullNoYes (nullptr)
Can point to another variable laterNoYes
Syntax to useLike a normal variableNeeds * and ->

Do not return a reference to a local variable

The local variable is destroyed when the function ends, so the reference would point to nothing. Modern GCC even refuses to compile this code:

int& bad() {
    int local = 5;
    return local;              // local dies when the function ends
}

int main() {
    bad();
}
Output

Dangling.cpp: In function 'int& bad()':
Dangling.cpp:3:12: error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
3 | return local; // local dies when the function ends
| ^~~~~

Note: Rule: small types (int, double) by value, big types by const&, and use a normal reference only when the function must change the argument. Next: C++ Pointers.

Congratulations! Chapter Finished. Learn more about the similar topics:
Exercises & Assignments
No Content Found.
Interview Questions & Answers
No Content Found.