How to Use absl::Span in Abseil C++ for Type-Safe Non-Owning Views

absl::Span<T> is a lightweight, non-owning view over contiguous sequences that eliminates raw pointer parameters while providing iterator support and bounds-checked access at zero runtime cost.

The absl::Span template, defined in the abseil/abseil-cpp repository at absl/types/span.h, offers a safer alternative to passing raw pointers and lengths to functions. It behaves similarly to absl::string_view but generalizes to any element type, allowing APIs to accept std::vector, std::array, C-style arrays, or any container exposing data() and size() without template overload explosion.

Core Design and Memory Model

An absl::Span is a trivial struct containing only a pointer and a size_t length. As documented in lines 20-26 of absl/types/span.h, it never allocates memory or copies elements; it merely references existing data. The caller must ensure the underlying storage outlives the span to avoid undefined behavior from dangling references.

Constructing absl::Span Views

Implicit Construction from Containers

When passing a container to a function expecting absl::Span<const T>, the compiler performs an implicit conversion. According to lines 35-41 in absl/types/span.h, any container providing data() and size() methods can convert to a read-only span automatically.

std::vector<int> vec = {1, 2, 3};
ProcessInts(vec);  // Implicitly converts to Span<const int>

Explicit Construction for Mutable Access

To create a mutable absl::Span<T> that allows modification of the underlying data, use the explicit constructor with raw pointers or non-const arrays. Lines 46-53 of absl/types/span.h define these constructors, which require the element type to be non-const.

int arr[] = {10, 20, 30};
absl::Span<int> mutable_span(arr);  // Explicit construction
mutable_span[1] = 99;               // Modifies arr

Factory Helpers: MakeSpan and MakeConstSpan

The factory functions MakeSpan and MakeConstSpan, defined at lines 86-110 in absl/types/span.h, deduce the element type automatically. absl::MakeSpan returns a mutable span when possible, while absl::MakeConstSpan always returns Span<const T>.

auto s1 = absl::MakeSpan(vec);        // Span<int> if vec is non-const
auto s2 = absl::MakeConstSpan(vec);   // Span<const int>

Mutable vs. Read-Only Access

Abseil distinguishes between mutable and const access at the type level. As implemented in lines 36-43, implicit conversions yield Span<const T>, preventing accidental modification. To obtain a mutable Span<T>, you must explicitly construct it or use MakeSpan on a non-const reference (lines 46-53).

Safe Element Access and Bounds Checking

absl::Span provides two access patterns with different safety guarantees:

  • operator[] provides unchecked access. Lines 33-39 in absl/types/span.h indicate that debug builds include hardening assertions, but production builds perform no bounds checking.
  • at() performs bounds checking and throws std::out_of_range if the index exceeds the span's size, as documented in the same region.

Use at() when safety is critical; use operator[] only after manual validation or in performance-critical loops where bounds are pre-verified.

Slicing and Sub-views

You can create new spans referring to subsets of the original data without copying elements. Lines 44-66 and 70-84 of absl/types/span.h define the following operations:

  • subspan(pos, count) returns a view starting at pos with count elements.
  • first(n) and last(n) return views of the initial or final n elements.
  • remove_prefix(n) and remove_suffix(n) adjust the span boundaries in-place.

These operations are zero-cost abstractions returning new absl::Span instances with adjusted pointers and lengths.

Iteration and Comparisons

absl::Span supports full STL-style iteration, including begin(), end(), reverse iterators, and range-for loops (lines 73-90). Additionally, lines 30-84 implement lexicographic comparison operators (==, !=, <, etc.) that compare elements sequentially across spans of compatible types.

Complete Working Example

#include "absl/types/span.h"
#include <vector>
#include <iostream>

void PrintInts(absl::Span<const int> values) {
  for (int v : values) std::cout << v << ' ';
  std::cout << '\n';
}

int main() {
  // 1️⃣ From a std::vector (read-only view via implicit conversion)
  std::vector<int> vec = {1, 2, 3, 4, 5};
  PrintInts(vec);

  // 2️⃣ From a C-style array (mutable view)
  int arr[5] = {10, 20, 30, 40, 50};
  absl::Span<int> mutable_span(arr);
  mutable_span[2] = 99;
  PrintInts(arr);  // Output: 10 20 99 40 50

  // 3️⃣ Using the factory helper (deduces the element type)
  auto span = absl::MakeSpan(vec);
  span.remove_prefix(1);  // View now {2,3,4,5}
  PrintInts(span);

  // 4️⃣ Sub-spans
  auto sub = absl::MakeSpan(arr).subspan(1, 3);  // {20,99,40}
  PrintInts(sub);

  // 5️⃣ First / last helpers
  auto head = absl::MakeSpan(vec).first(2);  // {1,2}
  auto tail = absl::MakeSpan(vec).last(2);   // {4,5}
  PrintInts(head);
  PrintInts(tail);
}

Summary

  • Non-owning reference: absl::Span stores only a pointer and length; the underlying data must outlive the span (lines 20-26 in absl/types/span.h).
  • Flexible construction: Accept containers, raw arrays, or use MakeSpan/MakeConstSpan for type deduction (lines 35-41, 86-110).
  • Safety options: Use at() for guaranteed bounds checking; operator[] relies on debug-only hardening assertions (lines 33-39).
  • Zero-cost slicing: Create sub-views with subspan, first, and last without copying data (lines 44-66).
  • Full iteration: Compatible with range-for loops and standard algorithms via begin()/end() (lines 73-90).

Frequently Asked Questions

What is the difference between absl::Span and std::span?

absl::Span predates the C++20 std::span and provides similar semantics with additional factory helpers and Abseil-specific hardening assertions. While std::span is standardized, absl::Span remains necessary for codebases supporting C++11 or C++14, and it integrates with Abseil's debugging infrastructure.

Does absl::Span own the memory it points to?

No. As implemented in lines 20-26 of absl/types/span.h, the span stores only a pointer and a size value. It is the caller's responsibility to ensure the referenced memory remains valid for the duration of the span's lifetime to avoid dangling references.

How do I create a mutable absl::Span from a const container?

You cannot safely create a mutable absl::Span<T> from a const container. Implicit conversions always yield Span<const T> (lines 36-43), and attempting to force a mutable view requires const-casting, which violates type safety. Use Span<const T> for read-only operations or copy the data to a mutable buffer first.

Is absl::Span bounds-checked in production builds?

Only the at() method performs bounds checking in all builds by throwing std::out_of_range. The operator[] access is unchecked in production; lines 33-39 indicate that bounds checks occur only via hardening assertions in debug builds. For guaranteed safety in production code, validate indices before using operator[] or use at().

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →