Daily bit(e) of C++ | handling C arrays with std::span
2 min readMay 12, 2024
Daily bit(e) of C++ ♻️53, Safely wrapping C-style arrays using C++20 std::span.
Passing data around as C-style arrays might be unavoidable when interacting with legacy code or C APIs. This can lead to errors when keeping track of the array size.
C++20 introduced std::span, a view that can wrap a contiguous memory block in a range interface. This allows us to safely use algorithms and views to process data without copying it into a C++ container.
std::span can also be converted to a std::span of std::byte, giving access to underlying object representation.
#include <cstdint>
#include <span>
#include <vector>
#include <ranges>
size_t read(char* buffer, size_t size);
int get_data(char** buffer, size_t* size);
char buffer[16];
auto view = std::span(buffer);
// Call C API using a wrapped buffer
size_t cnt = read(view.data(), view.size());
// Process a sub-view based on the number of actually read bytes
for (auto v : view.subspan(0, cnt)) {}
char* buff;
size_t length;
int ret = get_data(&buff, &length);
if (ret != 0) { return ret; }
// Wrap a C buffer into a std::span
auto buffer_view = std::span(buff, length);
// std::span works as any other range, e.g. reverse iteration:
for (auto it = buffer_view.rbegin(); it != buffer_view.rend(); ++it) {}
// or combining with views:
for (auto v : buffer_view | std::views::drop(8)) {}
struct Data {
int x;
int y;
};
std::vector<Data> data{{2,3},{1,5},{4,4}};
// Acces the underlying representation:
std::span<std::byte> bytes = std::as_writable_bytes(std::span(data));