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
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