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::Allocateto create a new buffer sized viaComputeCapacity - 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, andpush_backuse identical guardsinsertvalidates withif (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 bykOptimalInlinedSizeinStorage::GetInlinedCapacity()and triggers a single heap allocation when exceeded - Maximum size is bounded by the allocator and
size_typelimits, enforced byABSL_PREDICT_FALSEguards inmax_size() - Exceeding inline capacity causes automatic transition to heap storage via
MallocAdapter::AllocateinStorage::Initialize - Exceeding maximum size throws
std::length_errorviaThrowStdLengthErrorrather than causing undefined behavior - All guards are located in
absl/container/inlined_vector.hwith storage logic inabsl/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →