absl::FixedArray — 런타임 크기 stack 배열
#한 줄 요약
absl::FixedArray<T, N>은 생성 시점 크기는 결정되지만 그 이후 변경되지 않는 배열이다. 임계값 N 이하면 stack에 inline 저장, 초과하면 heap으로. C99 VLA(variable-length array)의 안전한 C++ 대체이며, std::vector의 자동 alloc을 피하고 싶은 짧은 수명 버퍼에 적합하다.
#동기
함수 안에서 임시 버퍼가 필요한데 크기가 런타임에 결정되는 경우가 흔하다.
void Process(absl::string_view input) { std::vector<char> buf(input.size()); // 항상 heap alloc // 버퍼 사용}대부분의 입력이 짧다면 매 호출마다 alloc이 발생하는 것은 낭비다. alloca 또는 C99 VLA로 stack 할당을 시도할 수도 있지만 둘 다 안전 문제가 있다 — 큰 크기에서 stack overflow.
FixedArray는 크기에 따라 분기한다. 작으면 stack, 크면 heap.
void Process(absl::string_view input) { absl::FixedArray<char, 256> buf(input.size()); // input.size() ≤ 256이면 stack, 아니면 heap}두 경우의 메모리 배치를 그림으로 보면 다음과 같다.
#API와 사용법
#include "absl/container/fixed_array.h"
namespace absl {template <typename T, size_t N = inline_default, typename A = std::allocator<T>>class FixedArray { public: explicit FixedArray(size_t n); FixedArray(size_t n, const T& fill); FixedArray(std::initializer_list<T> init); template <typename Iter> FixedArray(Iter first, Iter last);
T& operator[](size_t i); T& at(size_t i); T* data(); size_t size() const; bool empty() const; T* begin(); T* end(); // ...};}크기는 생성 시 한 번 결정된다. resize, push_back, insert는 없다.
absl::FixedArray<int, 16> a(n); // 0으로 초기화되지 않음 (trivial T)absl::FixedArray<int, 16> b(n, 0); // 0으로 채움absl::FixedArray<int, 16> c{1, 2, 3, 4}; // 4 원소
for (int& x : a) x = compute();#inline 임계값 N
기본 N은 kInlineBytesDefault(헤더에 정의)를 sizeof(T)로 나눈 값. 보통 inline 저장 공간이 256바이트 정도다. 명시적으로 지정 가능.
// 64개까지 stackabsl::FixedArray<int, 64> a(n);
// 0개 — 항상 heapabsl::FixedArray<int, 0> b(n);N=0으로 명시하면 항상 heap. std::vector와 비슷하나, 크기 고정이 명시되는 장점.
#내부 구현
FixedArray는 union 같은 구조다.
// absl/container/fixed_array.h (요약)template <typename T, size_t N, typename A>class FixedArray { size_t size_; T* data_;
union { char inline_storage_[N * sizeof(T)]; // heap-alloc 시 사용하지 않음 };
public: explicit FixedArray(size_t n) : size_(n) { if (n <= N) { data_ = reinterpret_cast<T*>(inline_storage_); } else { data_ = AllocateHeap(n); } ConstructDefault(data_, n); }
~FixedArray() { DestroyAll(); if (size_ > N) DeallocateHeap(); }};data_가 inline buffer 또는 heap을 가리킨다. 사용 쪽은 분기 인지 없이 data(), operator[]로 접근한다.
stack 할당이라도 생성자에서 T를 초기화한다. trivial T는 비초기화 옵션이 있지만, 일반적으로 호출 분기 시 명시 초기화 자리에 채우는 패턴.
#std::vector / std::array 비교
| 항목 | std::array | std::vector | absl::FixedArray |
|---|---|---|---|
| 크기 결정 | compile time | runtime | runtime |
| 크기 변경 | X | O | X |
| storage | stack | heap | stack(if ≤N) / heap |
| alloc-free fast path | O | X | O |
| 초기화 강제 | X (uninit OK) | O (zero) | trivial은 uninit, non-trivial은 default |
std::array는 크기가 컴파일 타임. std::vector는 항상 heap. FixedArray는 그 사이.
#코드 리뷰 포인트
1. 짧은 임시 버퍼
// 회피 — 매 호출 heap allocvoid Encode(absl::string_view in, std::string* out) { std::vector<char> tmp(in.size() * 2); // ...}
// Goodvoid Encode(absl::string_view in, std::string* out) { absl::FixedArray<char, 1024> tmp(in.size() * 2); // 대부분 입력에서 stack 사용}2. fanout 버퍼
// N개 worker로 분배void Dispatch(const Task& t, size_t worker_count) { absl::FixedArray<TaskPart, 16> parts(worker_count); for (size_t i = 0; i < worker_count; ++i) { parts[i] = MakePart(t, i, worker_count); } // 보통 worker_count ≤ 16, stack 경로}3. C API의 out 버퍼
ssize_t needed = some_c_function(nullptr, 0);absl::FixedArray<char, 256> buf(needed);some_c_function(buf.data(), needed);작은 경우 stack, 큰 경우 heap. VLA보다 안전.
#안티패턴
resize 가정
FixedArray는 resize/push_back이 없다. 크기 변경이 필요하면 std::vector 또는 absl::InlinedVector (Part 5-06).
과도하게 큰 N
absl::FixedArray<int, 100000> a(n); // sizeof(FixedArray) ≥ 400 KBstack frame이 400KB 이상이 된다. 깊은 호출 stack에서 위험. N은 대부분 입력이 들어가는 작은 값으로.
stack overflow 가능성 인지 부족
absl::FixedArray<int, 256> a(n);// n이 256 이하면 stack// 그런데 sizeof(int)*256 = 1KB가 매 호출 stack 사용// 재귀 함수면 깊이 1000에서 1MBFixedArray도 stack frame을 차지한다. 재귀나 깊은 호출 안에서는 신중히.
#정리
FixedArray<T, N>은 생성 시 결정, 이후 고정 크기 배열.- 크기 ≤ N이면 stack, 초과면 heap.
- VLA의 안전한 C++ 대체. resize 없음.
- 짧은 임시 버퍼, fanout, C API 버퍼에 적합.
- N은 흔한 입력이 들어가는 작은 값으로.
#다음 편
Part 5-06 — InlinedVector에서 크기 변경이 가능한 small-buffer optimization 버전을 본다.
#관련 항목
Abseil Code Review · 32 of 79
- 1 Abseil Code Review — Google production-grade C++ 라이브러리 분석
- 2 Abseil 개요 — Google이 std를 보완한 이유
- 3 Abseil 설계 철학 — std 호환과 추가 기능의 균형
- 4 Abseil 빌드와 의존성 — Bazel vs CMake
- 5 Abseil LTS vs HEAD 릴리스 모델 분석
- 6 Abseil Versioning과 ABI 호환성 정책
- 7 Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
- 8 Abseil ABSL_PREDICT_TRUE/FALSE — branch hint
- 9 absl::LogSeverity — 로그 레벨 타입
- 10 Abseil type_traits — negation·conjunction·void_t
- 11 Abseil Conformance·Policy 분석
- 12 Abseil Memory utilities 분석
- 13 Abseil raw_logging — heap-free 로깅
- 14 Abseil thread_annotations — clang TSA 통합
- 15 absl::Status — exception-free error handling
- 16 absl::StatusOr<T> — 값 또는 에러
- 17 absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
- 18 absl::Status payload — 구조화된 에러 컨텍스트
- 19 absl::Status ↔ exception 변환 패턴
- 20 absl::string_view — non-owning 문자열 참조
- 21 absl::string_view 함정 — dangling·c_str·임시 객체
- 22 absl::StrCat — 가변 인자 문자열 연결과 AlphaNum
- 23 absl::StrSplit — Delimiter·Predicate·컨테이너 변환
- 24 absl::StrJoin — 컨테이너 결합과 Formatter
- 25 absl::StrFormat — type-safe printf·FormatSpec
- 26 Abseil ASCII 함수 — locale-free 분류·대소문자 변환
- 27 Abseil Escape — CEscape·HexEscape·Base64
- 28 absl::flat_hash_map — Swiss Table 기반 hash map
- 29 absl::flat_hash_set — set 버전 Swiss Table
- 30 absl::node_hash_map — stable pointer가 필요할 때
- 31 absl::btree_map — sorted·cache-friendly B-tree
- 32 absl::FixedArray — 런타임 크기 stack 배열
- 33 absl::InlinedVector — small buffer optimization
- 34 Abseil Swiss Table internals — control byte·SIMD probing
- 35 absl::Mutex — reader-writer·fairness·deadlock 검출
- 36 absl::Mutex Conditional Critical Section — Await로 cv 없애기
- 37 absl::Notification — once-only signal
- 38 absl::BlockingCounter·Barrier — 다중 thread 조율
- 39 absl::Mutex annotations — clang thread-safety로 race를 컴파일 타임에
- 40 absl::Time·Duration 분석 — 단단한 type
- 41 absl::Time Format·Parse
- 42 absl::CivilTime 분석
- 43 absl::time_zone 분석
- 44 absl::Time mocking — 테스트 친화 시간
- 45 absl::BitGen — 모던 난수 생성기
- 46 Abseil Random Distributions — Uniform·Exponential
- 47 Abseil Mocking Random — 테스트 결정성
- 48 Abseil Random Seeding·Entropy
- 49 absl::int128·uint128 분석
- 50 absl::bits — popcount·countl_zero
- 51 absl::optional vs std::optional
- 52 absl::variant 분석
- 53 absl::span 분석
- 54 absl::any 분석
- 55 absl::compare — three-way 비교
- 56 Abseil utility — apply·in_place
- 57 Abseil AbslHashValue 분석
- 58 Abseil HashState chaining
- 59 Abseil Custom hashable 구현
- 60 Abseil LOG·VLOG·CHECK 분석
- 61 Abseil LogSink 분석
- 62 Abseil LogEntry·structured logging
- 63 Abseil Stack trace·failure_signal_handler
- 64 ABSL_FLAG 정의 분석
- 65 Abseil ParseCommandLine 동작
- 66 Abseil Flag introspection·validation
- 67 Google 스타일의 Abseil 사용 패턴
- 68 Abseil 자주 보는 anti-pattern
- 69 std → absl 마이그레이션 전략
- 70 absl::Cleanup — 함수 종료 시 실행 보장
- 71 Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
- 72 absl::function_ref와 any_invocable — 함수 객체 전달의 두 축
- 73 absl::bind_front와 Overload — 함수 객체 보조 도구
- 74 absl::Cord — 분산 시스템용 대용량 문자열
- 75 absl::from_chars·SimpleAtoi — 빠른 숫자 변환
- 76 absl::Cord vs std::string — 선택 기준과 메모리 프로파일
- 77 absl::GetStackTrace와 Symbolize — crash 시 readable stack
- 78 absl::ComputeCrc32c — 하드웨어 가속 체크섬
- 79 absl::PeriodicSampler — 적응형 샘플링·jitter 회피
관련 글
Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
absl::c_* algorithm wrapper — container 전체를 받아 begin/end 자동 처리, STL algorithm의 한 줄 boilerplate를 제거.
같은 시리즈에서 이어 읽기
absl::InlinedVector — small buffer optimization
Part 5-06: absl::InlinedVector — std::vector + 작으면 stack, 커지면 heap. SBO 패턴의 표준 도구.
같은 시리즈에서 이어 읽기
absl::btree_map — sorted·cache-friendly B-tree
Part 5-04: absl::btree_map — std::map(red-black tree)의 B-tree 대체, cache locality와 메모리 효율, sorted 컨테이너의 새 기준.
같은 시리즈에서 이어 읽기