Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why use references for mutable variables in c++

I'm new to c++. I came across some code and got confused

vector<int> vec{3,1,4,1,5};
vector<int> &vecRef = vec;
auto vecCopy = vecRef; // makes copy of vec
auto &vecRef2 = vecRef; // reference

I read about the usage of reference types in c++ and I understand why it's useful for immutable types. But for mutable types like vectors, what's the difference between vector vecCopy = vec and vector& vecRef = rec? Aren't they both alias to vec?

like image 576
Kathryn Avatar asked Jan 21 '26 10:01

Kathryn


2 Answers

Difference between references and values.

One of the features of C++ is that it distinguishes between references and values. A lot of other languages don't do this. Let's say you have a vector:

std::vector<int> v1 = {1, 2, 3};

Creating a deep copy of this vector is really simple:

auto copy_of_v1 = v1;

We can prove it by changing copy_of_v1:

std::cout << (v1 == copy_of_v1) << '\n'; // Prints 1, for true

copy_of_v1[1] = 20; // copy_of_v1 == {1, 20, 3} now

std::cout << (v1 == copy_of_v1) << '\n'; // Prints 0, for false

Use cases for references.

References have three big use cases: - Avoiding a copy by storing/using a reference - Getting additional information out of a function (by passing it a reference, and letting it modify the reference) - Writing data structures / container classes

We've seen the first case already, so let's look at the other two.

Using references to write functions that modify their input. Let's say you wanted to add the ability to append elements to vectors using +=. An operator is a function, so if it's going to modify the vector, it needs to have a reference to it:

// We take a reference to the vector, and return the same reference
template<class T>
std::vector<T>& operator +=(std::vector<T>& vect, T const& thing) {
    vect.push_back(thing); 
    return vect;
}

This allows us to append elements to the vector just like it was a string:

int main() {
    std::vector<int> a;

    ((a += 1) += 2) += 3; // Appends 1, then 2, then 3

    for(int i : a) {
        std::cout << i << '\n'; 
    }
}

If we didn't take the vector by reference, the function wouldn't be able to change it. This means that we wouldn't be able to append anything.

Using references to write containers.

References make it easy to write mutable containers in C++. When we want to provide access to something in the container, we just return a reference to it. This provides direct access to elements, even primitives.

template<class T>
class MyArray {
    std::unique_ptr<T[]> array;
    size_t count; 
   public:
    T* data() {
       return array.get();
    }
    T const* data() {
       return array.get();
    }
    MyArray() = default;         // Default constructor
    MyArray(size_t count)        // Constructs array with given size
      : array(new T[count])
      , count(count) {}
    MyArray(MyArray const& m)    // Copy constructor
      : MyArray(count) {
        std::copy_n(m.data(), count, data();
    }
    MyArray(MyArray&&) = default;// Move constructor

    // By returning a reference, we can access elements directly 
    T& operator[](size_t index) {
       return array[index]; 
    }
};

Now, when using MyArray, we can directly change and modify elements, even if they're primitives:

MyArray<int> m(10); // Create with 10 elements

m[0] = 1;           // Modify elements directly

m[0]++;             // Use things like ++ directly
like image 139
Alecto Irene Perez Avatar answered Jan 24 '26 11:01

Alecto Irene Perez


But for mutable types like vectors, what's the difference between vector vecCopy = vec and vector& vecRef = rec? Aren't they both alias to vec?

No. One is a copy of the entire vector. The other is a reference to the same.

Your example code is contrived. I can't think of any reasons why you would do this:

vector<int> vec{3,1,4,1,5};
vector<int> &vecRef = vec;

You pass variables by reference all the time. But I can't imagine a reason why I'd make a reference to a local variable like this, other than to illustrate an example of references as opposed to copies.

So: vecCopy is a whole DIFFERENT vector with its own contents. At the end of your code, it's identical in contents to vec, but after that, you can add to one or the other and they begin to diverge. vecRef is a reference to the exact same data. If you think of them as (under the hood) pointers, they point to the same object.

like image 20
Joseph Larson Avatar answered Jan 24 '26 12:01

Joseph Larson