absl::InlinedVector Size Limits: Inline Capacity vs. Maximum Size Explained

absl::InlinedVector enforces two distinct size limits: an inline capacity N that stores elements in an embedded buffer without heap allocation, and a hard maximum size bounded by allocator limits and size_type constraints, with exceeding the former triggering automatic heap allocation and the latter throwing std::length_error.

The absl::InlinedVector container in Google's Abseil C++ library provides a hybrid storage model that balances stack performance with heap flexibility. Understanding its size limits is crucial for performance-sensitive applications that rely on this optimization. This article examines the exact boundaries defined in the Abseil source code and the precise behavior when those boundaries are crossed.

The Two Size Limits of absl::InlinedVector

According to the Abseil C++ implementation, absl::InlinedVector<T, N, A> maintains two distinct capacity boundaries that govern its storage lifecycle.

Inline Capacity (N)

The inline capacity represents the number of elements that can be stored in the object's embedded buffer without any heap allocation. This value is computed as static_cast<size_type>(kOptimalInlinedSize) inside Storage::GetInlinedCapacity(), with the implementation defined in absl/container/internal/inlined_vector.h at lines 408-412.

Maximum Size (max_size())

The maximum size is the absolute upper bound on element count, calculated as the smaller of the allocator's max_size() and half of std::numeric_limits<size_type>::max(). This is implemented in InlinedVector::max_size() within absl/container/inlined_vector.h (lines 28-34).

What Happens When Inline Capacity Is Exceeded

When size() exceeds the inline capacity N, the vector automatically transitions from embedded storage to heap allocation.

In absl/container/internal/inlined_vector.h around line 180, the Storage::Initialize routine checks if (new_size > GetInlinedCapacity()). When this condition triggers:

  • The allocator invokes MallocAdapter::Allocate to create a new buffer sized via ComputeCapacity
  • Existing elements are moved (or copied if necessary) into the newly allocated storage
  • The internal flag GetIsAllocated() is set to true
  • Subsequent operations behave exactly like std::vector

This transition causes a single allocation, after which the container operates as a standard dynamic array.

What Happens When Maximum Size Is Exceeded

Every mutating operation that increases element count validates against max_size() using ABSL_PREDICT_FALSE guards. If the requested size exceeds the maximum, the library calls ThrowStdLengthError, which throws a std::length_error with a descriptive message.

Key locations in absl/container/inlined_vector.h:

  • Constructor at line 38: if (ABSL_PREDICT_FALSE(n > max_size()))
  • assign, resize, reserve, emplace_back, and push_back use identical guards
  • insert validates with if (ABSL_PREDICT_FALSE(s > max_size() - size()))

Unlike undefined behavior in raw arrays, exceeding the maximum size results in a catchable exception with a message like "InlinedVector::reserve failed length check".

Practical Code Example

#include "absl/container/inlined_vector.h"
#include <iostream>

int main() {
  // Inline capacity is 4. No heap allocation occurs.
  absl::InlinedVector<int, 4> v;
  for (int i = 0; i < 4; ++i) v.push_back(i);
  std::cout << "size = " << v.size()
            << ", capacity = " << v.capacity() << '\n';   // → 4 / 4

  // Exceed the inline capacity → heap allocation.
  v.push_back(42);
  std::cout << "size = " << v.size()
            << ", capacity = " << v.capacity() << '\n';   // → 5 / >4

  // Exceed the absolute maximum size → throws.
  try {
    v.reserve(v.max_size() + 1);
  } catch (const std::length_error& e) {
    std::cout << "Caught exception: " << e.what() << '\n';
  }
}

Output:


size = 4, capacity = 4
size = 5, capacity = 8
Caught exception: InlinedVector::reserve failed length check

Summary

  • Inline capacity (N) is determined by kOptimalInlinedSize in Storage::GetInlinedCapacity() and triggers a single heap allocation when exceeded
  • Maximum size is bounded by the allocator and size_type limits, enforced by ABSL_PREDICT_FALSE guards in max_size()
  • Exceeding inline capacity causes automatic transition to heap storage via MallocAdapter::Allocate in Storage::Initialize
  • Exceeding maximum size throws std::length_error via ThrowStdLengthError rather than causing undefined behavior
  • All guards are located in absl/container/inlined_vector.h with storage logic in absl/container/internal/inlined_vector.h

Frequently Asked Questions

What is the default inline capacity for absl::InlinedVector?

The default inline capacity is specified by the template parameter N, which is passed to Storage::GetInlinedCapacity() and computed as static_cast<size_type>(kOptimalInlinedSize). This value is typically optimized for cache line alignment and stored in the internal header at absl/container/internal/inlined_vector.h (lines 408-412).

Does absl::InlinedVector throw exceptions when resizing?

Yes, when the requested size exceeds max_size(), the container throws std::length_error through the ThrowStdLengthError mechanism. This occurs in constructors, reserve, resize, insert, and other growth operations, providing safety bounds checking that raw arrays lack.

Can I check if absl::InlinedVector has moved to heap storage?

Yes, you can indirectly detect this by comparing capacity() against the template parameter N. Once capacity() exceeds N, the vector has transitioned to heap allocation managed by MallocAdapter::Allocate, though the public API does not expose the GetIsAllocated() flag directly.

Is there a performance penalty when exceeding inline capacity?

The transition incurs a single allocation cost and element-move overhead when switching from the embedded buffer to heap storage. After this transition, performance characteristics match those of std::vector, as subsequent operations work on the heap-allocated buffer referenced by the Storage implementation.

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 →