C++ for Systems Programmers

std::span and std::string_view

Imagine you want to write a function that processes a sequence of bytes, and you want it to work whether the bytes came from a std::vector, a C array, a std::string, or a raw malloc'd buffer — without copying them and without forcing the caller into one container type. A view solves this: it is a small object that holds just a pointer to existing data plus a length, borrowing that data without owning it. std::span is the view over a contiguous sequence of any element type; std::string_view is the specialized view over a sequence of characters.

Concretely, a std::span<T> is essentially a (pointer, count) pair: it does not allocate, does not copy, and does not free anything — it simply describes a window onto memory that lives somewhere else. Pass a std::vector or a C array to a function taking std::span<int> and the function sees the same elements in place. std::string_view is the same idea for text: it replaces the old habit of passing const char* (no length) or const std::string& (forces a std::string, may copy) with a uniform (pointer, length) view that any string-like source can produce cheaply. Because they are non-owning, both are tiny to pass and turn 'works on my container' functions into 'works on any contiguous data' functions.

Why it matters: views are a clean expression of the zero-overhead principle — you get one flexible interface with no copies and no allocation. The honest and crucial caveat is lifetime: a view does not keep its underlying data alive, so it is only valid as long as that data is. A std::string_view into a temporary std::string, or a std::span into a std::vector that then reallocates (or goes out of scope), becomes a dangling view — a use-after-free that reads freed or moved memory. Views are borrowed pointers with bounds; treat them with the same lifetime discipline you would give a raw pointer.

void sum(std::span<const int> xs); std::vector<int> v{1,2,3}; sum(v); int a[]{4,5}; sum(a); // one function, no copies, works on both

A span borrows (pointer + length) from any contiguous source; the same function accepts a vector and a C array without copying either.

A view never extends the lifetime of what it points at: a string_view returned from a function that built a temporary std::string dangles immediately, and a span into a vector is invalidated the moment that vector reallocates on growth. Outliving the data is a use-after-free, plain and simple.

Also called
non-owning viewsborrowed ranges非擁有視圖借用範圍