Array Spans and std::span

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?

Abstract art representing computer programming

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.

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved