Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Efficient Vector Parameter Passing
Pass vectors to functions by reference to avoid expensive copies.
Passing std::vector to functions
Like any object in C++, a std::vector can be passed to functions. However, because vectors can contain substantial amounts of data, passing them by value creates expensive copies. The solution: pass vectors by reference.
Passing vectors by const reference
When a function needs to read vector data without modifying it, pass by const reference:
#include <iostream>
#include <vector>
void displayFirst(const std::vector<int>& numbers)
{
if (!numbers.empty())
std::cout << "First element: " << numbers[0] << '\n';
}
int main()
{
std::vector temps { 72, 68, 75, 71, 69 };
displayFirst(temps);
return 0;
}
This avoids copying the entire vector while preventing accidental modifications.
Specifying element types explicitly
Because std::vector is a template, we must specify the element type when declaring function parameters:
#include <iostream>
#include <vector>
void showFirstItem(const std::vector<double>& values) // Must specify <double>
{
if (!values.empty())
std::cout << values[0] << '\n';
}
int main()
{
std::vector prices { 29.99, 15.50, 42.00 };
showFirstItem(prices);
return 0;
}
This also means the function only accepts vectors of that specific type:
#include <iostream>
#include <vector>
void showFirstItem(const std::vector<double>& values)
{
if (!values.empty())
std::cout << values[0] << '\n';
}
int main()
{
std::vector prices { 29.99, 15.50, 42.00 };
showFirstItem(prices); // OK: vector<double>
std::vector counts { 10, 20, 30 };
showFirstItem(counts); // Error: vector<int> doesn't match vector<double>
return 0;
}
CTAD doesn't work for function parameters
You might think to use Class Template Argument Deduction (CTAD) to avoid specifying the type:
#include <iostream>
#include <vector>
void showFirstItem(const std::vector& values) // Error: CTAD not allowed here
{
if (!values.empty())
std::cout << values[0] << '\n';
}
int main()
{
std::vector prices { 29.99, 15.50, 42.00 };
showFirstItem(prices);
return 0;
}
Unfortunately, CTAD works for variable definitions but not for function parameters. We need another approach.
Using function templates for generic vector handling
Function templates let us write functions that work with vectors of any element type:
#include <iostream>
#include <vector>
template <typename T>
void showFirstItem(const std::vector<T>& values)
{
if (!values.empty())
std::cout << values[0] << '\n';
}
int main()
{
std::vector prices { 29.99, 15.50, 42.00 };
showFirstItem(prices); // Instantiates showFirstItem(const std::vector<double>&)
std::vector counts { 10, 20, 30 };
showFirstItem(counts); // Instantiates showFirstItem(const std::vector<int>&)
return 0;
}
The compiler automatically instantiates the appropriate function version for each vector type.
Generic templates for maximum flexibility
For even greater flexibility, we can accept any container type:
#include <iostream>
#include <vector>
template <typename T>
void showFirstItem(const T& container)
{
if (!container.empty())
std::cout << container[0] << '\n';
}
int main()
{
std::vector prices { 29.99, 15.50, 42.00 };
showFirstItem(prices);
std::vector counts { 10, 20, 30 };
showFirstItem(counts);
return 0;
}
This works with any type that supports empty() and operator[], making it extremely versatile. In C++20, you can use an abbreviated function template:
#include <iostream>
#include <vector>
void showFirstItem(const auto& container)
{
if (!container.empty())
std::cout << container[0] << '\n';
}
int main()
{
std::vector prices { 29.99, 15.50, 42.00 };
showFirstItem(prices);
std::vector counts { 10, 20, 30 };
showFirstItem(counts);
return 0;
}
The trade-off: this ultra-generic approach might allow nonsensical types to compile until runtime errors occur.
Runtime assertions for vector length requirements
Consider a function that assumes a minimum vector length:
#include <iostream>
#include <vector>
template <typename T>
void displayThirdElement(const std::vector<T>& data)
{
std::cout << data[2] << '\n';
}
int main()
{
std::vector temps { 72, 68 }; // Only 2 elements!
displayThirdElement(temps); // Undefined behavior
return 0;
}
This compiles but causes undefined behavior when executed. Add a runtime assertion to catch such errors:
#include <cassert>
#include <iostream>
#include <vector>
template <typename T>
void displayThirdElement(const std::vector<T>& data)
{
assert(data.size() >= 3 && "Vector must have at least 3 elements");
std::cout << data[2] << '\n';
}
int main()
{
std::vector temps { 72, 68 };
displayThirdElement(temps); // Triggers assertion in debug builds
return 0;
}
For compile-time length checking, prefer std::array instead of std::vector (covered in lesson 17.3).
Efficient Vector Parameter Passing - Quiz
Test your understanding of the lesson.
Practice Exercises
Passing std::vector to Functions
Practice passing vectors to functions by value, reference, and const reference. Learn the performance implications of each approach.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!