# 4. Memory Management and Lifetime ## Ownership model Use explicit ownership categories: - `std::unique_ptr` for exclusive ownership - `std::shared_ptr` only when shared lifetime is required - raw pointer/reference for non-owning access only ## Rules - prefer RAII for all resource lifetimes - avoid raw `new`/`delete` in ordinary C++ ownership flows - if raw handles are required at ABI boundaries, wrap internals in RAII - document lifetime assumptions for borrowed pointers ## Non-owning span/view rules `dtl::distributed_span` and binding-layer local views are borrowed views: - never transfer ownership through span/view construction - ensure the owning container/handle outlives every borrowed span/view - refresh span/view objects after structural operations (`resize`, `redistribute`, or owner recreation) ## ABI boundary exceptions C ABI handles are opaque pointer types by design. This is acceptable when: - creation and destroy APIs are paired and tested - validation/magic checks exist at boundaries - cleanup is deterministic on all error paths ## Python binding lifetime rules - keep native handles in wrapper classes with deterministic destruction - preserve Python object ownership for NumPy view lifetimes - avoid leaking callback/request state on async paths ## Fortran binding lifetime rules - keep ownership in C ABI layer - Fortran holds `type(c_ptr)` handles and must call destroy functions - ensure wrappers do not copy or orphan owning pointers ## Memory review checklist - no ownership cycles without reason - no leaked request/window/context handles - no dangling view owners - all early-return error paths free allocated resources