Using Span as a Function Parameter

What are the benefits of using std::span as a function parameter instead of a reference to a container like std::vector or std::array?

Using std::span as a function parameter has several benefits over using a reference to a specific container type:

Flexibility

A function that takes a std::span can be called with any contiguous sequence of elements, regardless of how those elements are actually stored. This could be a std::vector, a std::array, a built-in array, or even another std::span. This makes the function more flexible and reusable.

#include <span>
#include <vector>
#include <array>
#include <iostream>

void PrintElements(std::span<const int> elements) {
  for (int i : elements) {
    std::cout << i << " ";
  }
  std::cout << "\n";
}

int main() {
  std::vector<int> vec{1, 2, 3};
  std::array<int, 4> arr{4, 5, 6, 7};
  int c_arr[] = {8, 9, 10};

  PrintElements(vec);
  PrintElements(arr);
  PrintElements(c_arr);
}
1 2 3
4 5 6 7
8 9 10

No Unnecessary Copying

When you pass a container by value, a copy of the container is made. For large containers, this can be expensive. When you pass a reference to a container, no copying is done, but the function is tied to a specific container type. With std::span, no copying is done, and the function can work with any container type.

Clarity of Intent

Using std::span makes it clear that the function only needs a view of the elements, and does not need to modify the container itself. This can make the code easier to understand and maintain.

Const-Correctness

You can use std::span<const T> to indicate that the function will not modify the elements. This is not possible with a non-const reference to a container.

void ProcessElements(
  std::span<const int> elements) {
  // elements cannot be modified here
}

Avoid Dangling References

If a function takes a reference to a container, and that container is a temporary object, the reference will be left dangling after the temporary object is destroyed. With std::span, the caller needs to ensure that the original data outlives the span.

void ProcessElements(
  const std::vector<int>& elements) {
  // Dangling reference if elements is a temporary
}

void ProcessElements(
  std::span<const int> elements) {
  // No dangling reference, but caller must ensure
  // original data outlives the span
}

However, std::span is not always the best choice. If your function needs to modify the container itself (e.g., add or remove elements), then you need to take the container by reference. Also, std::span doesn't work well with non-contiguous containers like std::list or std::map.

Array Spans and std::span

A detailed guide to creating a "view" of an array using std::span, and why we would want to

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Span vs Vector in C++
When should I use std::span over std::vector in C++? What are the key differences and trade-offs between these two types?
Creating a Span from a Vector
How can I create a std::span from a std::vector in C++? Can you provide an example?
Span Size and Stack Overflow
Is there a limit to the size of a std::span? Could creating a very large std::span lead to a stack overflow?
Lifetime of a Span
What happens if I create a std::span from a vector, and then the vector goes out of scope? Is it safe to continue using the span?
Modifying Elements Through a Span
If I modify an element through a std::span, does it affect the original data? Can you show an example?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant