How to Pass Vector by Reference in C++

Jinku Hu Feb 12, 2024
  1. Use the vector<T> &arr Notation to Pass a Vector by Reference in C++
  2. Use the const vector<T> &arr Notation to Pass a Vector by Reference in C++
  3. Use the vector<T>* arr Notation to Pass a Vector by Reference in C++
  4. Use std::reference_wrapper to Pass a Vector by Reference in C++
  5. Conclusion
How to Pass Vector by Reference in C++

Passing vectors by reference in C++ is an optimization technique to enhance both performance and memory efficiency, especially when dealing with large datasets. This article explores several methods to achieve this, each offering its advantages based on specific use cases.

Use the vector<T> &arr Notation to Pass a Vector by Reference in C++

One effective way to pass vectors efficiently in C++ is by using the vector<T> &arr notation, allowing functions to operate directly on the original vector without creating unnecessary copies.

The vector<T> &arr notation indicates passing a reference to a vector of type T. The ampersand (&) denotes a reference, meaning the function receives the memory address of the original vector rather than a new copy.

This approach is beneficial as it avoids the overhead of duplicating the entire vector and enables modifications to the original vector within the function.

Code Example:

#include <iostream>
#include <iterator>
#include <vector>

using std::copy;
using std::cout;
using std::endl;
using std::vector;

vector<int> &multiplyByTwo(vector<int> &arr) {
  for (auto &i : arr) {
    i *= 2;
  }
  return arr;
}

int main() {
  vector<int> arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  cout << "Original Vector - ";
  copy(arr.begin(), arr.end(), std::ostream_iterator<int>(cout, "; "));
  cout << endl;

  auto arr_mult_by2 = multiplyByTwo(arr);

  cout << "Modified Vector - ";
  copy(arr_mult_by2.begin(), arr_mult_by2.end(),
       std::ostream_iterator<int>(cout, "; "));
  cout << endl;

  return EXIT_SUCCESS;
}

In the code example, the multiplyByTwo function takes a reference to a vector of integers (vector<int> &arr) as its parameter. Inside the function, a range-based for loop is used to iterate through each element of the vector, and each element is then multiplied by two.

The function returns a reference to the modified vector, allowing the changes to directly impact the original vector.

vector<int> &multiplyByTwo(vector<int> &arr) {
  for (auto &i : arr) {
    i *= 2;
  }
  return arr;
}

In the main function, a vector named arr is initialized with a sequence of integers from 1 to 10. The elements are displayed using the copy function along with an ostream_iterator to display the initial state of the vector.

The multiplyByTwo function is then called, passing the vector arr as an argument. The returned reference, assigned to arr_mult_by2, holds the modified vector.

Following the function call, the program proceeds to display the modified vector using the same technique with the copy function and ostream_iterator. The output provides a clear illustration of the vector’s transformation.

Output:

Original Vector - 1; 2; 3; 4; 5; 6; 7; 8; 9; 10;
Modified Vector - 2; 4; 6; 8; 10; 12; 14; 16; 18; 20;

The code emphasizes the efficiency gained by passing vectors by reference, as it eliminates the need for creating redundant copies of the entire vector. By directly manipulating the original vector within the function, both memory and processing resources are conserved.

This approach is particularly advantageous when dealing with large datasets, contributing to improved performance and code readability.

Use the const vector<T> &arr Notation to Pass a Vector by Reference in C++

Another efficient vector manipulation method in C++ is the const vector<T> &arr notation. This notation, employing the const qualifier, ensures that the passed vector remains unaltered within the function scope.

The const vector<T> &arr notation signifies the passing of a constant reference to a vector of type T. The addition of the const keyword informs the compiler that the function won’t modify the vector it receives as an argument.

This not only helps in maintaining the original state of the vector but also aids the compiler in optimizing machine code for better performance. While seemingly a subtle detail, the use of const provides clarity in function contracts and can assist in avoiding unintended modifications.

Code Example:

#include <iostream>
#include <iterator>
#include <vector>

using std::copy;
using std::cout;
using std::endl;
using std::vector;

vector<int> &multiplyByTwo(vector<int> &arr) {
  for (auto &i : arr) {
    i *= 2;
  }
  return arr;
}

void findInteger(const vector<int> &arr) {
  int target = 10;
  for (const auto &i : arr) {
    if (i == target) {
      cout << "Found - " << target << " in the array" << endl;
      return;
    }
  }
  cout << "Not found - " << target << " in the array" << endl;
}

int main() {
  vector<int> arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  auto arr_mult_by2 = multiplyByTwo(arr);

  cout << "Modified Vector - ";
  copy(arr_mult_by2.begin(), arr_mult_by2.end(),
       std::ostream_iterator<int>(cout, "; "));
  cout << endl;

  findInteger(arr);
  findInteger(arr_mult_by2);

  return EXIT_SUCCESS;
}

In this code example, the multiplyByTwo function remains the same, taking a reference to a vector of integers and multiplying each element by two. The new addition is the findInteger function, which takes a constant reference to a vector of integers (const vector<int> &arr) as its parameter.

Inside the function, it searches for a specific integer (target) within the vector and prints whether it was found or not.

void findInteger(const vector<int> &arr) {
  int target = 10;
  for (const auto &i : arr) {
    if (i == target) {
      cout << "Found - " << target << " in the array" << endl;
      return;
    }
  }
  cout << "Not found - " << target << " in the array" << endl;
}

In the main function, a vector named arr is initialized, and the multiplyByTwo function is called, modifying the vector. The modified vector is then displayed using the copy function and ostream_iterator.

Subsequently, the findInteger function is called twice, once for the original vector and once for the modified vector, showcasing the usage of the const notation to prevent unintentional modifications.

Output:

Modified Vector - 2; 4; 6; 8; 10; 12; 14; 16; 18; 20;
Found - 10 in the array
Not found - 10 in the array

As shown in the output, the original vector remains unaltered during the search operation in the findInteger function, emphasizing the importance of maintaining vector integrity when modifications are undesired.

Use the vector<T>* arr Notation to Pass a Vector by Reference in C++

Let’s discuss another efficient vector manipulation technique in C++: the vector<T>* arr notation. This notation involves passing a pointer to a vector of integers, allowing functions to operate directly on the original vector.

The vector<int>* arr notation signifies the passing of a pointer to a vector of integers. The asterisk (*) denotes a pointer, indicating that the function receives the memory address of the original vector.

Using a pointer grants the ability to directly modify the original vector and is particularly useful when handling large datasets or when the function needs to allocate memory for the vector dynamically. However, it also comes with the responsibility of managing memory properly, especially if the vector is dynamically allocated.

Code Example:

#include <iostream>
#include <iterator>
#include <vector>

using std::copy;
using std::cout;
using std::endl;
using std::vector;

void multiplyByTwo(vector<int>* arr) {
  for (auto& i : *arr) {
    i *= 2;
  }
}

int main() {
  vector<int> arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  multiplyByTwo(&arr);

  cout << "Modified Vector - ";
  copy(arr.begin(), arr.end(), std::ostream_iterator<int>(cout, "; "));
  cout << endl;

  return EXIT_SUCCESS;
}

In this code example, the multiplyByTwo function takes a pointer to a vector of integers (vector<int>* arr). Inside the function, the pointer is dereferenced using the asterisk (*) to access the original vector, and each element is then multiplied by two.

This approach allows direct modification of the original vector through the pointer.

void multiplyByTwo(vector<int>* arr) {
  for (auto& i : *arr) {
    i *= 2;
  }
}

In the main function, a vector named arr is initialized with a sequence of integers. The multiplyByTwo function is called, passing the memory address of the vector using the address-of operator (&).

The modified vector is then displayed using the copy function and ostream_iterator.

Output:

Modified Vector - 2; 4; 6; 8; 10; 12; 14; 16; 18; 20;

This output demonstrates the effectiveness of using the vector<int>* arr notation. The original vector is modified directly through a pointer, eliminating the need for creating additional copies.

While using pointers adds flexibility, it is crucial to manage memory properly and consider the implications, especially in scenarios involving dynamic memory allocation.

Use std::reference_wrapper to Pass a Vector by Reference in C++

The std::reference_wrapper from the <functional> header provides another convenient workaround for passing vectors by reference. std::reference_wrapper is a lightweight wrapper that behaves like a reference but can be stored in containers that require assignable types.

It is particularly useful when you need to pass references around, such as when working with function parameters. In the context of passing vectors by reference, std::reference_wrapper allows us to create a reference-like object that can be easily passed to functions, overcoming restrictions on directly storing references in certain contexts.

It provides a clean and expressive way to pass references without resorting to pointers.

Code Example:

#include <functional>
#include <iostream>
#include <iterator>
#include <vector>

using std::copy;
using std::cout;
using std::endl;
using std::reference_wrapper;
using std::vector;

void multiplyByTwo(vector<int>& arr) {
  for (auto& i : arr) {
    i *= 2;
  }
}

int main() {
  vector<int> arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  reference_wrapper<vector<int>> arrRef(arr);

  multiplyByTwo(arrRef);

  cout << "Modified Vector - ";
  copy(arr.begin(), arr.end(), std::ostream_iterator<int>(cout, "; "));
  cout << endl;

  return EXIT_SUCCESS;
}

In this code, the multiplyByTwo function takes a reference to a vector of integers (vector<int>& arr) as its parameter. To pass the vector by reference using std::reference_wrapper, we create a reference_wrapper<vector<int>> named arrRef, which wraps the original vector.

The function is then called, allowing us to modify the original vector through the reference wrapper.

void multiplyByTwo(vector<int>& arr) {
  for (auto& i : arr) {
    i *= 2;
  }
}

In the main function, a vector named arr is initialized with a sequence of integers. A reference_wrapper is created, wrapping the vector, and passed to the multiplyByTwo function.

This enables the function to operate on the original vector directly. The modified vector is then displayed using the copy function and ostream_iterator.

Output:

Modified Vector - 2; 4; 6; 8; 10; 12; 14; 16; 18; 20;

The output shows the original vector is efficiently modified through the reference wrapper, offering a clean and expressive solution for scenarios where reference semantics are desired within functions.

Conclusion

Choosing the appropriate method to pass vectors by reference in C++ depends on the specific requirements of your code. Whether you prioritize efficiency, read-only access, flexibility with pointers, or the clean syntax provided by std::reference_wrapper, understanding these methods will allow you to make informed decisions for optimal vector manipulation in your C++ programs.

Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Related Article - C++ Vector