Memory management is the single most consequential skill in systems and ML code. A GPU inference engine allocates large float buffers for weights and activations, passes them between functions, and must free them at exactly the right moment — no sooner (use-after-free), no later (memory leak). C++ gives you two layers of control: raw pointers, which let you address memory directly with no overhead, and smart pointers, which wrap raw pointers in RAII objects that automatically release memory when the owning object goes out of scope. This page covers both layers, plus struct padding and alignment, which determines how the compiler lays struct fields out in memory — a detail that becomes highly relevant when writing memory-efficient tensor descriptors.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/VrajPatel105/cpp-gpu-inference/llms.txt
Use this file to discover all available pages before exploring further.
Raw Pointers and References
A pointer stores the memory address of another variable. The& operator takes the address of a variable; the * operator dereferences a pointer to read or write the value it points to. %p is the printf format specifier for printing addresses.
Pointers vs. References
Pointer (*)
Stores a memory address. Can be null, can be reassigned to point elsewhere,
and can be used with pointer arithmetic. Requires explicit
* to
dereference.Reference (&)
An alias for an existing variable. Cannot be null, cannot be reseated after
initialization, and is accessed with the same syntax as the original
variable — no
* required.Struct Padding and Memory Alignment
The compiler inserts invisible padding bytes between struct fields to satisfy alignment requirements.alignof(T) returns the alignment boundary (in bytes) that type T requires. An int (4 bytes) must start at an address divisible by 4; if the preceding field leaves the offset at an odd position, the compiler inserts padding to reach the next aligned boundary.
struct A and struct B are 8 bytes here, but the padding lands in different positions. In a struct with more varied field types, reordering fields from largest to smallest alignment can eliminate padding entirely and reduce total struct size.
Smart Pointers
Smart pointers from<memory> wrap a raw pointer and tie its lifetime to an owning object. When the owner goes out of scope, the destructor is called automatically and the heap allocation is freed. This pattern is called RAII (Resource Acquisition Is Initialization).
unique_ptr — Exclusive Ownership
A unique_ptr is the sole owner of its allocation. Ownership can be transferred with std::move, but not copied. When the unique_ptr goes out of scope, the memory is freed immediately.
shared_ptr — Shared Ownership with Reference Counting
Multiple shared_ptr instances can share ownership of the same object. An internal reference counter tracks how many owners exist; the object is destroyed when the counter reaches zero. use_count() lets you inspect the current count.
weak_ptr — Non-Owning Observer
A weak_ptr observes a shared_ptr-managed object without contributing to the reference count. When the last shared_ptr releases ownership, the object is destroyed even if weak_ptr instances still exist — those pointers become dangling and can be detected via expired().
Why smart pointers matter for ML code. A neural network layer may
allocate hundreds of megabytes for weight matrices. With raw pointers, an
early
return or a thrown exception can skip the delete call, leaking the
entire allocation. Smart pointers make memory safety automatic — the
destructor runs regardless of how the function exits, whether normally or via
exception. This is RAII: tying resource lifetime to object lifetime so the
compiler enforces cleanup for you.Quick Reference
- unique_ptr
- weak_ptr