References & Pass-by-reference

রেফারেন্স ও পাস বাই রেফারেন্স

Read: ~30 min 16 practice problems

1. What Is a Reference?

A reference is an alias — another name for an existing variable. Once bound, it can never refer to anything else. It cannot be null. It is the cleanest way C++ has to share a variable instead of copying it.

Reference হলো একটি existing variable-এর অন্য নাম। একবার bind হয়ে গেলে অন্য কিছুতে refer করতে পারে না, এবং null হতে পারে না। এটি pointer-এর চেয়ে অনেক নিরাপদ।
ref.cpp
#include <iostream>

int main() {
    int x = 10;
    int& r = x;        // r is another name for x
    r = 42;             // modifies x
    std::cout << x << "\n"; // 42
}

2. Pass by Value vs Pass by Reference

pass.cpp
#include <iostream>

void byValue(int n)  { n = 99; }      // modifies a copy
void byRef(int& n)    { n = 99; }      // modifies the original

int main() {
    int a = 5, b = 5;
    byValue(a);  byRef(b);
    std::cout << a << " " << b << "\n";  // 5 99
}

3. const T& — Read-only by Reference

For large objects (strings, vectors), copying is expensive. Pass const T& — no copy, no mutation:

constref.cpp
#include <iostream>
#include <string>
#include <vector>

void printAll(const std::vector<std::string>& v) {
    for (const auto& s : v) std::cout << s << "\n";
}

int main() {
    std::vector<std::string> cities = {"Dhaka", "Chittagong", "Sylhet"};
    printAll(cities);
}

4. Reference vs Pointer

AspectReferencePointer
Can be nullNoYes (nullptr)
RebindableNoYes
Syntaxr = x;*p = x;
Address-ofImplicitExplicit (&x)
Use whenAlways available; shareOptional; complex ownership
Rule of thumb Prefer T& over T* unless you specifically need null or rebinding.

5. Returning References

You can return a reference to enable modification or to avoid copying — but never return a reference to a local!

retref.cpp
int& smallest(int& a, int& b) {
    return (a < b) ? a : b;
}

int main() {
    int x = 7, y = 3;
    smallest(x, y) = 0;  // y is now 0
}

// DON'T DO THIS:
// int& bad() { int x = 5; return x; }  // dangling reference!
Dangling reference Returning a reference to a function-local variable causes undefined behavior — the variable is destroyed when the function returns.

6. Practice Problems

  1. Write void swap(int& a, int& b).
    ✨ Show Answer
    void swap(int& a, int& b) { int t = a; a = b; b = t; }
  2. Why is const std::string& usually preferred over std::string in parameters?
    ✨ Show Answer

    Avoids copying the entire string content. const ensures the function won't modify it. Best of both: efficiency + safety.

  3. Can a reference be rebound?
    ✨ Show Answer

    No. int& r = x; r = y; assigns y's value to x via r; r still refers to x.

  4. What's wrong with: int& r;
    ✨ Show Answer

    References must be initialized at declaration. There is no "null reference".

  5. Write a function that doubles each element in a vector via reference.
    ✨ Show Answer
    void doubleAll(std::vector<int>& v) {
        for (auto& x : v) x *= 2;
    }
  6. Why is returning a local by reference a bug?
    ✨ Show Answer

    The local is destroyed when the function returns. The reference would point to invalid memory — undefined behavior.

  7. Make this safe by reference: void increment(int x) { x++; }
    ✨ Show Answer
    void increment(int& x) { x++; }
  8. Can you have a vector of references?
    ✨ Show Answer

    No — std::vector<int&> is illegal. References aren't objects in their own right. Workaround: std::vector<std::reference_wrapper<int>>.

  9. When is pass-by-value actually preferable?
    ✨ Show Answer

    For small types (int, double, char) — passing by reference adds an indirection, while value passing fits in a register. Also when you'd copy anyway inside the function.

  10. Demonstrate that a reference doesn't introduce a new variable.
    ✨ Show Answer
    int x = 5;
    int& r = x;
    std::cout << &x << " " << &r << "\n"; // same address
  11. Difference between const int& and int const&?
    ✨ Show Answer

    None — they are exactly the same. const binds left of the type when both are present. Style: const int& is more common.

  12. Write int& getElement(std::vector<int>& v, size_t i).
    ✨ Show Answer
    int& getElement(std::vector<int>& v, size_t i) {
        return v[i];
    }

    Allows getElement(v, 0) = 42;

  13. What does auto& x = v[0]; do?
    ✨ Show Answer

    Binds x as a reference to v[0]. Modifying x modifies v[0]. Without &, you'd get a copy.

  14. Pass by const reference vs by value — which is faster for int?
    ✨ Show Answer

    Pass by value. An int fits in a register; passing a reference adds a memory indirection. For built-ins, by value wins.

  15. What does void f(std::string s) do that void f(const std::string& s) doesn't?
    ✨ Show Answer

    The first copies the caller's string. The second binds a reference (no copy). Use the first only when you need a modifiable local copy anyway.

  16. Show that int& r = 5; doesn't compile.
    ✨ Show Answer

    5 is a temporary (rvalue). A non-const lvalue reference cannot bind to it. const int& r = 5; is OK — const refs can extend a temporary's lifetime.

Summary

A reference is an alias — never null, never rebindable. Use T& to allow modification, const T& to read without copying. Prefer references over pointers when you don't need null or rebinding. Never return a reference to a local variable.

Next Module → Arrays, std::array & std::vector basics.