C++ PROGRAMMING ยท 12 MIN STUDY

string_view and span: non-owning views

Pass text and contiguous sequences efficiently using non-owning views while respecting object lifetime.

Learning objectives

  • Explain why string_view and span do not own their elements.
  • Pass text without requiring a std::string copy.
  • Use span to describe a contiguous sequence.
  • Identify dangling-view bugs.

Prerequisites: understand references, arrays, vectors, and object lifetime. Review References, Arrays, Vectors, and Scope and lifetime. This lesson uses std::string_view (C++17) and std::span (C++20); compile the complete examples in C++20 or later.

What is a view?

A view describes access to data owned somewhere else. It usually stores a pointer and a size rather than owning or copying the elements. This can make function interfaces flexible and efficient, but the owner must outlive the view.

std::string_view

#include <string_view>
#include <string>
#include <iostream>
void print_name(std::string_view name) {
    std::cout << name << '\n';
}
int main() {
    std::string text = "OpenLearn";
    print_name(text);
    print_name("C++");
}

string_view can refer to a std::string, string literal, or another valid character sequence. It does not extend the lifetime of the source. Avoid returning a view to a local string.

Danger: returning a dangling view

std::string_view bad_name() {
    std::string local = "temporary";
    return local; // dangling after function returns
}

The local string is destroyed at function exit. The returned view then refers to storage whose lifetime has ended. Return an owning std::string when the function creates the text.

std::span

#include <span>
#include <iostream>
void print_values(std::span<const int> values) {
    for (int value : values) std::cout << value << ' ';
}
int main() {
    int data[]{2, 4, 6};
    print_values(data);
}

span is a non-owning view over a contiguous sequence. It carries a pointer and a count. It can refer to arrays, vectors, and other contiguous storage. span<const int> allows reading values without modifying them through the span.

Bounds and lifetime

A span knows its size, but operator[] does not perform bounds checking. Use at() only if the span implementation/library version provides it (C++26 standard span adds at; ordinary C++20 span does not). In C++20, check indexes against size() yourself.

Choosing an interface

  • Use const std::string& when you need an owning string object without copying.
  • Use std::string_view for read-only text that may come from different string-like sources.
  • Use std::span<T> for a non-owning view over contiguous T elements.
  • Use an owning container when the function must retain the data beyond the caller's lifetime.

Practice

  1. Write a function that counts vowels in a string_view.
  2. Write a function that sums a span of integers.
  3. Explain why returning string_view to a local std::string is unsafe.
Show solutions
  1. Loop over characters in the view and count vowels.
  2. Loop over the span and accumulate into an integer.
  3. The local string is destroyed before the caller uses the returned view.

Summary

Views avoid ownership and copying but do not manage lifetime. Choose them for short-lived access to data whose owner is guaranteed to remain alive.

References