Welcome to LibFP’s C++ Documentorial!#

This documentation page is designed less like a direct reference and more like a tutorial. If you would instead prefer a reference… full generated documentation can be found here.

This is the C++ version of this document the C version can be found here.

Features#

  • Automatic bounds tracking for allocated memory

  • Stack and heap allocation support

  • Views (non-owning references to memory regions)

  • Iterator support for range-based operations

  • C and C++ compatibility

This header provides modern C++ wrappers around the C-style fat pointer library, including:

  • RAII automatic memory management

  • Type-safe view classes

  • STL-compatible iterators and ranges

  • Convenient operator overloads

  • Compile-time sized arrays

Single Header Library#

This library can be used standalone from the rest of the library… however certain functions need FP_IMPLEMENTATION defined before the library is included to get definitions. Be sure to #define FP_IMPLEMENTATION in only one source file!

Basic C++ Usage#

#include "pointer.hpp"
// Automatic memory management
fp::auto_free numbers = fp::malloc<int>(100);
for(size_t i = 0; i < numbers.size(); i++)
    numbers[i] = i * 2;

// Automatically freed when goes out of scope
// Manual memory management
fp::pointer<float> data = fp::malloc<float>(50);
data.fill(3.14f);
data.free_and_null(); // Preferred over .free()
// Compile-time sized array
fp::array<double, 10> fixed;
fixed[0] = 1.0;
template<typename T>
struct auto_free : public T#

RAII wrapper that automatically frees the wrapped pointer on destruction.

This class wraps any type with a .free method a bool convertible raw field and construction from a (possibly null) pointer and ensures automatic cleanup when the object goes out of scope. It implements proper move semantics and copy on assignment.

void process() {
    auto_free<fp::pointer<int>> data(fp::malloc<int>(100));
    data[0] = 42;
    // Automatically freed when data goes out of scope
}

// Move semantics work correctly
auto_free<fp::pointer<int>> create() {
    auto_free<fp::pointer<int>> temp(fp::malloc<int>(10));
    return temp; // Moved, not freed
}
Template Parameters:

T – Wrapped pointer type (e.g., fp::pointer<int>)

template<typename T>
inline pointer<T> fp::malloc(size_t count = 1)#

Allocate a fat pointer on the heap.

// Allocate single element
fp::pointer<int> single = fp::malloc<int>();
*single = 42;

// Allocate array
fp::pointer<float> arr = fp::malloc<float>(100);
for(size_t i = 0; i < arr.size(); i++)
    arr[i] = i * 1.5f;

// Allocate for complex types
struct Point { int x, y; };
fp::pointer<Point> points = fp::malloc<Point>(50);
points[0] = {10, 20};

single.free();
arr.free();
points.free();

See also

fp_alloc() for a version that dynamically stack allocates.

RAII Allocation#

// Use with RAII for automatic cleanup
fp::raii::pointer<int> auto_arr = fp::malloc<int>(100);
fp::auto_free same_as_above = fp::malloc<int>(100);
// No need to call free() - automatic cleanup
Template Parameters:

T – Element type

Parameters:

count – Number of elements to allocate (default: 1)

Returns:

New fat pointer with allocated memory

template<typename T>
struct pointer : public fp::wrapped::pointer<T>, public fp::pointer_crtp<T, pointer<T>>#

Main fat pointer class (fp::pointer) with manual memory management.

This is the primary fat pointer class that provides manual memory management with explicit free() calls. For automatic memory management, use fp::raii::pointer or fp::auto_free.

The pointer class combines the wrapped::pointer base (for raw pointer access) with pointer_crtp (for fat pointer operations), providing a complete interface for working with dynamically allocated arrays with bounds checking.

// Manual memory management
fp::pointer<int> data = fp::malloc<int>(100);
data[0] = 42;
data.realloc(200);  // Resize to 200 elements
data.free();

// Or use clone for deep copy
fp::auto_free original = fp::malloc<int>(10);
original.fill(5);
fp::pointer<int> copy = original.clone();
copy.free();
original.free(false); // ERROR: Using non-nullifying free on an auto_free type will result in a double free!

Iteration Examples#

fp::auto_free arr = fp::malloc<int>(50);

// Range-based for loop
for(int& val : arr)
    val = 10;

// STL algorithms
std::sort(arr.begin(), arr.end());
std::iota(arr.begin(), arr.end(), 0);

// Manual iteration
for(size_t i = 0; i < arr.size(); i++)
    arr[i] *= 2;

Working with Views#

fp::auto_free data = fp::malloc<int>(100);

// Create view of middle section
auto middle = data.view(25, 50);
for(int& val : middle) {
    val = 999;
}

// Create multiple views
auto first_half = data.view(0, 50);
auto second_half = data.view(50, 50);
Template Parameters:

T – Element type

Subclassed by fp::dynarray< char >, fp::dynarray< T >

template<typename T, size_t N>
struct array : public fp::pointer_crtp<T, array<T, N>>#

Fixed-size array (fp::array) with fat pointer interface.

This class provides a stack-allocated array with the same interface as fat pointers. It’s useful when you know the size at compile time and want to avoid heap allocation. The array is automatically destroyed when it goes out of scope.

// Create fixed-size array
fp::array<int, 10> arr;

// Initialize with initializer list
fp::array<float, 5> values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};

// Access elements
arr[0] = 42;
arr.fill(99);

// Use like any other fat pointer
for(int& val : arr)
    val *= 2;

// Create views
auto v = arr.view(2, 5);

// Check properties
assert(arr.size() == 10);
assert(arr.stack_allocated());
assert(!arr.heap_allocated());

// No need to free - automatically destroyed

Compile-Time Usage#

constexpr fp::array<int, 5> get_primes() {
    fp::array<int, 5> primes;
    primes[0] = 2;
    primes[1] = 3;
    primes[2] = 5;
    primes[3] = 7;
    primes[4] = 11;
    return primes;
}

constexpr auto primes = get_primes();
static_assert(primes[2] == 5);

Using as Function Parameters#

template<size_t N>
void process(fp::array<int, N>& arr) {
    for(size_t i = 0; i < arr.size(); i++)
        arr[i] *= 2;
}

fp::array<int, 10> data;
data.fill(5);
process(data);
assert(data[0] == 10);

STL Compatibility#

fp::array<int, 20> numbers;

// Use with STL algorithms
std::iota(numbers.begin(), numbers.end(), 1);
std::reverse(numbers.begin(), numbers.end());

// Convert to span
std::span<int> s = numbers.span();

Aggregate Operations#

fp::array<double, 100> data;
data.fill(1.0);

// Use front() and back()
data.front() = 0.0;
data.back() = 100.0;

// Create subviews
auto first_quarter = data.view(0, 25);
auto last_quarter = data.view(75, 25);

first_quarter.fill(2.0);
last_quarter.fill(3.0);
Template Parameters:
  • T – Element type

  • N – Number of elements (compile-time constant)

View Usage#

fp::auto_free arr = fp::malloc<int>(100);
// Create a view of part of the array
fp::view<int> v = arr.view(10, 20);
// Iterate over view
for(int& val : v)
    val = 2;

// Create subviews
auto subv = v.subview(5, 10);
template<typename T> fp::view : public struct __fp_view

Non-owning view (fp::view) over a contiguous sequence of elements.

A view is a lightweight, non-owning reference to a contiguous block of memory. It stores a pointer and size but does not manage the lifetime of the data. Views support subviews, iteration, and conversion to/from std::span (if previously included).

fp::auto_free arr = fp::malloc<int>(100);

// Create view of entire array
fp::view<int> full = fp::view<int>::make_full(arr.data());

// Create view of subset
fp::view<int> partial = full.subview(10, 20);

// Iterate
for(int& val : partial)
    val = 2;

// Access elements
partial[0] = 999;
Template Parameters:

T – Element type

STL Integration#

fp::auto_free data = fp::malloc<int>(50);
// Convert to std::span
std::span<int> s = data.span();
// Use with STL algorithms
std::sort(data.begin(), data.end());
std::fill(data.begin(), data.end(), 42);
// Range-based for loops
for(int& val : data)
    std::cout << val << "\n";

Dynamic Stack Allocation#

fp::pointer<int> arr = fp_alloca(int, 100);
arr.fill(42);

// Range-based for loops
for(int& val : data)
    std::cout << val << "\n";

// Don't free this pointer our store it in a RAII type!
// arr.free()
fp_alloca(type, _size)#

Allocate a typed fat pointer on the stack.

Best practices:

  • Use fp_alloca() for temporary buffers < 10KB

  • Use fp_malloc() for anything larger or with dynamic lifetime

  • Never return stack-allocated pointers

  • Be careful with recursion and stack allocations

void compute() {
    int* numbers = fp_alloca(int, 50);
    for(int i = 0; i < 50; i++) {
        numbers[i] = i * i;
    }
    printf("Length: %zu\n", fp_length(numbers));
    // Automatically freed
}

See also

fp_alloca() for type-safe version

See also

fp_malloc() for heap allocation

See also

fp_is_stack_allocated() to check allocation type

Warning

Stack allocations have limited size. Use fp_malloc() for large allocations.

Warning

Stack memory is only valid within the current scope. Do not return stack-allocated pointers from functions.

Parameters:
  • type – Element type

  • _size – Number of elements to allocate

Returns:

Typed pointer to allocated stack memory

Basic Dynamic Array Usage#

fp::dynarray<int> numbers;

// Add elements
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);

// Method chaining
numbers.reserve(100)
       .grow(5, 42)
       .push_back(99);

// Iteration
for(auto& n : numbers)
    std::cout << n << " ";

// Manual cleanup
numbers.free();
template<typename T>
struct dynarray : public fp::pointer<T>, public fp::dynarray_crtp<T, dynarray<T>>#

Dynamic array with manual memory management.

fp::dynarray is a std::vector-like container built on fat pointers. Provides automatic growth, efficient insertion/deletion, and full iterator support. Requires manual free() call or use fp::raii::dynarray for automatic cleanup.

Features:

  • Automatic capacity management with amortized O(1) push

  • Method chaining for fluent interface

  • Perfect forwarding with emplace operations

  • Automatic destructor calls for non-trivial types

  • STL-compatible interface

Basic Dynarray Usage#

fp::dynarray<int> numbers;

// Add elements
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);

// Method chaining
numbers.reserve(100)
       .grow(5, 42)
       .push_back(99);

// Iteration
for(auto& n : numbers)
    std::cout << n << " ";

// Manual cleanup
numbers.free();

Initializer List#

fp::dynarray<int> numbers = {1, 2, 3, 4, 5};
assert(numbers.size() == 5);
assert(numbers[2] == 3);

fp::dynarray<std::string> names = {"Alice", "Bob", "Charlie"};
assert(names.size() == 3);

numbers.free();
names.free();

Complex Types in a Dynarray#

struct Person {
    std::string name;
    int age;
    Person(std::string n, int a) : name(std::move(n)), age(a) {}
};

fp::dynarray<Person> people;

// In-place construction (no copies)
people.emplace_back("Alice", 30);
people.emplace_back("Bob", 25);
people.emplace(1, "Charlie", 35);  // Insert at position 1

// people: [Alice(30), Charlie(35), Bob(25)]

people.free();  // Destructors called automatically

Common Dynarray Operations#

fp::dynarray<int> data;
for(int i = 0; i < 100; i++)
    data.push_back(i);

// Delete range
data.delete_range(10, 20);

// Fast unordered delete (O(1))
data.swap_delete(5);

// Insert multiple elements
auto view = data.insert_uninitialized(0, 5);
for(size_t i = 0; i < view.size(); i++)
    view[i] = -1;

// Clone and concatenate
fp::dynarray<int> copy = data.clone();
data.concatenate_in_place(copy);

data.free();
copy.free();

STL Compatibility#

fp::dynarray<int> arr = {5, 2, 8, 1, 9};

// Use STL algorithms
std::sort(arr.begin(), arr.end());
std::reverse(arr.begin(), arr.end());

// Find element
auto it = std::find(arr.begin(), arr.end(), 5);
if(it != arr.end())
    std::cout << "Found at position: " << (it - arr.begin()) << "\n";

// Use with span (C++20)
std::span<int> s = arr.span();

arr.free();
Template Parameters:

T – Element type

Indices and Tables#