Ch9.16: C++ Standard Library Containers

Overview

The C++ standard library ships its own set of containers in the std:: namespace. If you are coming from another language or have not used C++ before, you may encounter these in existing codebases. This section introduces them and explains how they differ from fast_io.

In short: prefer fast_io containers. They are safer, faster, and more consistent. But you should still recognise the std:: equivalents so you can read other people’s code and understand the ecosystem.

1. Available Containers

std:: container fast_io:: equivalent Description
std::vector<T> ::fast_io::vector<T> Dynamic contiguous array.
std::deque<T> ::fast_io::deque<T> Double-ended queue (block-map layout).
std::list<T> ::fast_io::list<T> Doubly-linked list.
std::forward_list<T> ::fast_io::forward_list<T> Singly-linked list.
std::array<T, N> ::fast_io::array<T, N> Fixed-size array.
std::string ::fast_io::string Dynamic, null-terminated character sequence.
std::string_view ::fast_io::string_view Non-owning view over characters.
std::span<T> ::fast_io::span<T> Non-owning view over a contiguous sequence.
std::stack<T> ::fast_io::stack<T> LIFO adaptor.
std::queue<T> ::fast_io::queue<T> FIFO adaptor.
std::priority_queue<T> ::fast_io::priority_queue<T> Priority-based adaptor.

2. Basic Usage

The std:: containers are used in much the same way as fast_io ones. The main differences are in the header paths and the lack of some fast_io-specific features:


#include <vector>
#include <deque>
#include <string>
#include <iostream>

int main() {
    // std::vector — dynamic contiguous array
    ::std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    ::std::cout << "Size: " << v.size() << '\n';

    // std::deque — double-ended queue
    ::std::deque<int> d;
    d.push_front(10);
    d.push_back(20);

    // std::string — dynamic character sequence
    ::std::string s = "Hello";
    s += ", World!";
    ::std::cout << s << '\n';
}
Note: This tutorial uses fast_io throughout. You do not need to learn the std:: containers to follow along — everything we cover uses fast_io.

3. Key Differences

If you do encounter std:: containers, be aware of these differences:

Aspect std:: containers fast_io:: containers
Bounds checking operator[] is unchecked — out-of-bounds is undefined behaviour. at() throws std::out_of_range, but this adds significant overhead for bounds checking. Worse, an out-of-bounds access is already a bug — catching an exception at that point does not fix the underlying problem. Trying to recover from a program bug makes things worse compared to just terminating and restarting. operator[] is bounds-checked. Out-of-bounds calls fast_terminate() immediately — deterministic, no exception overhead, no false sense of recovery.
Allocation failure Throws std::bad_alloc. A failed heap allocation means the abstract machine is corrupted — there is no meaningful way to continue. Throwing an exception invites buggy recovery code that tries to limp along on a broken heap. Calls fast_terminate() — no exception unwinding, no attempt to recover from an unrecoverable state. The program is already corrupt; crash deterministically.
Logic bugs (empty front/back, OOB) Undefined behaviour. Silent memory corruption in release builds. Deterministic termination. Bugs are caught immediately.
Growth relocation Uses move constructors. For types with non-trivial moves, this can be slow. Uses memcpy when types are trivially relocatable — much faster.
Index-based operations No insert_index / erase_index. Must use iterators. Bounds-checked insert_index / erase_index on all eligible containers.
String formatting std::format (C++20) or std::stringstream — relatively slow. concat_fast_io + to<T> — compile-time optimised.
Unchecked variants None. Only operator[] is unchecked; everything else is checked via exceptions. Explicit _unchecked variants for performance-critical code.
Bit vector std::vector<bool> is a specialisation that packs bits but has a broken interface (proxy references). ::fast_io::bitvec is a separate, clean type with proper bit-level operations.

4. A Note on C++26 Hardening

C++26 introduces hardening for standard library containers — bounds checks on operator[], front(), back(), and iterator validity assertions. However, these containers were not designed to be hardened from the ground up. Retrofitting safety checks onto decades of existing ABI leads to problems:

fast_io containers were designed with safety from the start — no ODR issues, no opt-in confusion, and consistent deterministic termination across all builds.

5. Code Comparison

Here is the same program written with both libraries:

With fast_io (preferred)


#include <fast_io_dsal/vector.h>
#include <fast_io_dsal/string.h>
#include <fast_io.h>

int main() {
    ::fast_io::vector<::std::size_t> v;
    v.push_back(1zu);
    v.push_back(2zu);
    v.push_back(3zu);

    // Bounds-checked — terminates on out-of-bounds
    ::fast_io::io::println("v[0] = ", v[0zu]);

    // Index-based insert and erase
    v.insert_index(1zu, 99zu);  // [1, 99, 2, 3]
    v.erase_index(0zu);         // [99, 2, 3]

    // String formatting
    ::fast_io::string s = ::fast_io::concat_fast_io("Count: ", v.size());
    ::fast_io::io::println(s);
}

With std::


#include <vector>
#include <string>
#include <format>
#include <iostream>

int main() {
    ::std::vector<::std::size_t> v;
    v.push_back(1zu);
    v.push_back(2zu);
    v.push_back(3zu);

    // operator[] is unchecked — UB if out of bounds
    ::std::cout << "v[0] = " << v[0] << '\n';
    // v.at(0) is checked but throws an exception

    // Must use iterators for insert/erase
    v.insert(v.begin() + 1, 99zu);   // [1, 99, 2, 3]
    v.erase(v.begin());               // [99, 2, 3]

    // String formatting
    ::std::string s = ::std::format("Count: {}", v.size());
    ::std::cout << s << '\n';
}

6. Further Reading

For full documentation of the std:: containers, see cppreference — Container library. It provides exhaustive reference material for every std:: type, method, and overload.

However, for new code in this tutorial’s projects, always reach for the fast_io equivalent first.

Key takeaways