std::span
(C++20)std::span
is a non-owning view of a contiguous sequence of objects, introduced in C++20. It provides a lightweight, non-owning reference to a contiguous sequence of elements, offering a safer and more flexible alternative to pointer and size pairs. std::span
is particularly useful for passing array-like data to functions without copying and for working with subranges of containers.
#include <iostream>
#include <span>
void printNumbers(std::span<const int> numbers) {
for (const auto& num : numbers) {
std::cout << num << ' ';
}
std::cout << '\n';
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
printNumbers(arr);
return 0;
}
std::span
with a C-style array.printNumbers
function takes a std::span<const int>
as an argument, allowing it to work with any contiguous sequence of integers.main
, we create a simple integer array and pass it to printNumbers
.std::span
automatically deduces the size of the array, making it safer and more convenient than passing a pointer and size separately.#include <iostream>
#include <span>
#include <vector>
void modifyFirstHalf(std::span<int> numbers) {
auto firstHalf = numbers.first(numbers.size() / 2);
for (auto& num : firstHalf) {
num *= 2;
}
}
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5, 6};
std::cout << "Original vector: ";
for (int num : vec) std::cout << num << ' ';
std::cout << '\n';
modifyFirstHalf(vec);
std::cout << "Modified vector: ";
for (int num : vec) std::cout << num << ' ';
std::cout << '\n';
return 0;
}
std::span
can be used with std::vector
.modifyFirstHalf
function takes a std::span<int>
and modifies the first half of the elements.span::first()
to create a sub-span of the first half of the elements.std::span
provides a view into the existing memory.#include <iostream>
#include <span>
#include <array>
void processCoordinates(std::span<const double, 3> coord) {
std::cout << "X: " << coord[0] << ", Y: " << coord[1] << ", Z: " << coord[2] << '\n';
}
int main() {
std::array<double, 3> point3D = {1.0, 2.0, 3.0};
processCoordinates(point3D);
double rawPoint[] = {4.0, 5.0, 6.0};
processCoordinates(rawPoint);
// Uncommenting the following line would result in a compile-time error
// std::array<double, 4> point4D = {1.0, 2.0, 3.0, 4.0};
// processCoordinates(point4D); // Error: wrong number of elements
return 0;
}
processCoordinates
function takes a std::span<const double, 3>
, which specifies that it expects exactly 3 double
values.std::array
and C-style arrays to this function, as long as they have exactly 3 elements.#include <iostream>
#include <span>
#include <vector>
#include <stdexcept>
void processData(std::span<int> data) {
if (data.size() < 2) {
throw std::runtime_error("Data must contain at least 2 elements");
}
data[0] = data[data.size() - 1];
std::cout << "First element set to: " << data[0] << '\n';
}
int main() {
try {
std::vector<int> vec1 = {1, 2, 3, 4, 5};
processData(vec1);
std::vector<int> vec2 = {10};
processData(vec2); // This will throw an exception
}
catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << '\n';
}
return 0;
}
std::span
can be used with dynamic sizes and runtime checks.processData
function takes a dynamic std::span<int>
and performs a runtime check on its size.std::span
is a powerful addition to the C++ standard library, offering a safe and efficient way to work with contiguous sequences of objects. It provides several key benefits:
std::span
doesn't own the data it refers to, making it lightweight and efficient.std::array
, and std::vector
.std::span
avoids unnecessary copying of data.By using std::span
, C++ developers can write more robust and efficient code when dealing with contiguous sequences of objects, improving both safety and performance in their applications.