Summary
Passing std::vector in C++
Highlights
When passing a std::vector to a function, it's crucial to pass by (const) reference to avoid expensive copies. The element type of the std::vector must be explicitly specified in the function parameter. For example, a function expecting `const std::vector<int>&` cannot accept `std::vector<double>`.
Class Template Argument Deduction (CTAD) works when defining a `std::vector` from initializers (e.g., `std::vector primes{ 2, 3, 5 }`), but it doesn't currently work for deducing function parameter types. Attempting to use `const std::vector& arr` as a function parameter will result in a compile error.
To handle `std::vector`s of different element types, function templates are used. A template like `template <typename T> void passByRef(const std::vector<T>& arr)` allows the compiler to instantiate specific functions (e.g., `passByRef(const std::vector<int>&)` or `passByRef(const std::vector<double>&)`) based on the type of `std::vector` passed.
More generic templates, such as `template <typename T> void passByRef(const T& arr)`, can accept any object with an overloaded `operator[]`, including `std::vector`, `std::array`, or `std::string`. C++20 introduces abbreviated function templates using `const auto& arr` for the same purpose. While flexible, this approach can introduce bugs if an object that compiles but doesn't make semantic sense is passed.
Functions that access elements by index should validate the index to prevent undefined behavior from out-of-bounds access. While `assert(arr.size())` can be used for runtime checks in debug builds, a better practice is to avoid functions relying on a minimum vector length. For `constexpr` arrays, `static_assert` can check lengths at compile-time. The best practice is to design functions that don't implicitly rely on minimum array sizes.
A solution for a `printElement` function that takes a `std::vector` and an integer index is provided. It checks if the `index` is out of bounds (less than 0 or greater than or equal to `arr.size()`) and prints an error or the element's value accordingly. The `index` parameter is `int` to handle negative inputs, and `static_cast<std::size_t>(index)` is used for array access after validation.