Ch5.12: Pointers with vector, array, and string

Overview

Modern C++ containers provide safe, convenient abstractions over raw memory. However, the three major contiguous containers — ::fast_io::vector, ::fast_io::array, and ::fast_io::string — all expose raw pointers when needed.

In this chapter, you will learn:

1. ::fast_io::vector and pointers

::fast_io::vector<T> stores its elements in a contiguous block of memory. This means:


::fast_io::vector<int> v{1, 2, 3, 4};

int *p = v.data();            // pointer to v[0]
int *q = p + 2;               // points to v[2]

int a = v.index_unchecked(1); // unchecked v[1]
int b = v.front_unchecked();  // unchecked v[0]
int c = v.back_unchecked();   // unchecked v[3]

⚠️ Unchecked access never performs bounds checking.

Note: Bounds checking in fast_io is usually extremely cheap. When an out‑of‑range access is detected, fast_io simply calls fast_terminate() immediately, without printing diagnostics or performing expensive error handling. This makes checked access fast while still providing safety.

2. ::fast_io::array and pointers

::fast_io::array<T, N> is a fixed‑size container that behaves like a safer C‑style array.

It provides:


::fast_io::array<int, 3> a{10, 20, 30};

int *p = a.data();            // pointer to a[0]
int *q = p + 1;               // points to a[1]

int x = a.index_unchecked(2); // unchecked a[2]
int y = a.front_unchecked();  // unchecked a[0]
int z = a.back_unchecked();   // unchecked a[2]

⚠️ Unchecked functions never perform bounds checking.

Note: Bounds checking in fast_io is extremely cheap, because fast_terminate() is the only action taken on failure.

Unlike C‑style arrays, ::fast_io::array allows size 0.

3. ::fast_io::string and pointers

::fast_io::string stores characters in a contiguous block of memory. This means:


::fast_io::string s{"Hello"};

char *p = s.data();            // pointer to 'H'
char const *q = s.c_str();     // pointer to 'H', null-terminated

char a = s.index_unchecked(1); // unchecked 'e'
char b = s.front_unchecked();  // unchecked 'H'
char c = s.back_unchecked();   // unchecked 'o'

⚠️ Unchecked access does not validate bounds.

Note: Bounds checking in fast_io is extremely cheap, because fast_terminate() is called immediately on failure.

Reminder:
s.data() may not be null‑terminated.
s.c_str() is always null‑terminated.

4. Contiguous storage guarantees

All three containers guarantee that their elements are stored contiguously:

This means pointer arithmetic is valid as long as you stay within bounds.


int *p = v.data();
int *end = p + v.size();   // one past the end

This is identical to how C‑style arrays behave.

5. Containers do not decay

C‑style arrays decay automatically in most expressions. Containers do not.


int a[3]{1,2,3};
int *p = a;   // decay

But:


::fast_io::vector<int> v{1,2,3};

// int *p = v;   // ❌ does not compile

You must explicitly request a pointer using .data().

6. Pointer arithmetic with container storage

Once you obtain a pointer from .data(), pointer arithmetic works exactly as with C‑style arrays.


int *p = a.data();
int *q = p + 2;   // points to a[2]

The same applies to ::fast_io::string:


char *p = s.data();
char *q = p + 4;   // points to 'o'

As always, going out of bounds is undefined behavior.

7. ::std::to_address and container iterators

::std::to_address is the universal way to obtain a raw pointer from anything that behaves like a pointer.

This is important because container iterators are not raw pointers, even though they behave like them.

Example: ::fast_io::vector


auto it = v.begin();          
int *p = ::std::to_address(it);

Example: ::fast_io::array


auto it = a.begin();
int *p = ::std::to_address(it);

Example: ::fast_io::string


auto it = s.begin();
char *p = ::std::to_address(it);

::std::to_address is the modern, standard‑approved way to extract a raw pointer from an iterator.

8. Summary table

Container Contiguous? Pointer from .data() Null-terminated? Decay? Unchecked access?
::fast_io::vector<T> ✔ yes T* ❌ no ❌ no ✔ index/front/back_unchecked()
::fast_io::array<T,N> ✔ yes T* ❌ no ❌ no ✔ index/front/back_unchecked()
::fast_io::string ✔ yes char* ✔ via .c_str() ❌ no ✔ index/front/back_unchecked()

Key takeaways