Why does STL not provide general implementation of small object optimization (SSO/SBO/SOO/Arena, etc.)?
The C++ Standard Template Library (STL) does not provide a general implementation of small object optimization (SOO) primarily because its design philosophy prioritizes a clear separation of concerns, where containers manage object lifetime and memory layout but do not assume responsibility for optimizing the internal storage of the objects they contain. The STL's containers, such as `std::vector` or `std::string`, are generic and must work efficiently for any type `T`, imposing constraints that make a universal SOO implementation impractical. For instance, SOO typically requires storing a small buffer within the container object itself, which necessitates knowing a type's size and alignment at compile time to reserve appropriate space. However, a truly generic container cannot predetermine an optimal buffer size that benefits all types; what is "small" for a `char` is irrelevant for a large struct, and embedding a buffer large enough for the latter would bloat the container for all instantiations, harming performance in the common case. Moreover, SOO would interfere with the STL's strong exception safety guarantees and allocator support, as managing an internal buffer alongside dynamically allocated memory complicates move semantics, copy operations, and allocator-aware design.
The technical mechanisms required for a general SOO are also at odds with the STL's commitment to type-agnostic containers. Implementing SOO effectively demands type traits or compile-time introspection to decide whether to use the optimization, but the standard library historically avoided requiring such metadata for all types. While C++11 and later introduced `std::allocator_traits` and facilities like `std::is_nothrow_move_constructible`, a container would still need a heuristic—such as comparing `sizeof(T)` to a threshold—to activate SOO. This heuristic is inherently policy-based and application-specific; the STL leaves such policies to the user or specialized implementations like `std::function` or `std::any`, which do employ SOO because they have domain-specific knowledge. For example, `std::string` commonly implements SOO (often called short string optimization) because it is a concrete template specialization for `char`, where a buffer of 15-23 bytes is a known win. In contrast, a generic `std::vector<T>` cannot assume a universally beneficial threshold without risking wasted stack memory or inhibiting compiler optimizations like small buffer elision.
Furthermore, the STL's evolution has favored extensibility through custom allocators rather than baking in storage strategies that might not suit all use cases. The `std::pmr::polymorphic_allocator` and memory resources in C++17 provide a standardized arena-based approach, allowing users to achieve SOO-like benefits through specialized allocators without altering container implementations. This design aligns with the principle that containers manage sequences, while allocators manage storage; mixing the two by hardcoding SOO would reduce flexibility. Additionally, general SOO could break ABI stability, as changing the internal buffer size in a widely used container would alter its layout, incompatible with the strict ABI constraints that library vendors must maintain across compiler versions.
Ultimately, the absence of general SOO in the STL reflects a calculated trade-off: the library provides the tools—specialized containers, allocators, and type traits—for users to implement SOO where needed, while avoiding the complexity and overhead of a one-size-fits-all solution. This approach preserves the STL's generality, performance transparency, and adherence to zero-overhead principles, ensuring that containers remain lean and predictable for the majority of types that do not benefit from small buffer optimizations.