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

> Learn to use absl::Span in Abseil C++ for type-safe non-owning views. Eliminate raw pointers and gain bounds-checked access with zero runtime cost. Master efficient C++ data handling.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: how-to-guide
- Published: 2026-07-15

---

**`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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/absl/types/span.h), any container providing `data()` and `size()` methods can convert to a read-only span automatically.

```cpp
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`](https://github.com/abseil/abseil-cpp/blob/main/absl/types/span.h) define these constructors, which require the element type to be non-const.

```cpp
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`](https://github.com/abseil/abseil-cpp/blob/main/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>`.

```cpp
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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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

```cpp
#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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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()`.