Memory management
Decades ago, the designers of the classic BLAS made the wise decision to not internally allocate dynamically-sized arrays. Such an approach was (and is) viable because BLAS only operates on very simple datatypes: scalars and references to dense arrays of scalars.
RandBLAS, by contrast, needs to provide a polymorphic API with far more sophisticated datatypes.
This has led us to adopt a policy where we can internally allocate and deallocate dynamically-sized arrays
with the new [] and delete [] keywords, subject to the restrictions below.
Users are not bound to follow these rules, but deviations from them should be made with care.
Allocation and writing to reference members
We allocate memory with
new []only when necessary or explicitly requested.If a region of memory is allocated, it must either be deallocated before the function returns or attached to a RandBLAS-defined object that persists beyond the function’s scope.
We can only attach memory to objects by overwriting a null-valued reference member, and only when the object has an
own_memorymember that evaluates to true.We cannot overwrite an object’s reference member if there is a chance that doing so may cause a memory leak.
This restriction is in place regardless of whether
obj.own_memoryis true. It makes for very few cases when RandBLAS is allowed to overwrite a non-null reference member.
Deallocation
We deallocate memory only in destructors.
In particular, we never “reallocate” memory. If reallocation is needed, the user must manage the deletion of old memory and then put the object in a state where RandBLAS can write to it.
A destructor attempts deallocation only if
own_memoryis true.The destructor calls
delete []on a specific reference member if and only if that member is non-null.
What we do instead of overwriting non-null references
Let obj denote an instance of a RandBLAS-defined type where obj.member is a reference.
Suppose we find ourselves in a situation where obj.member is non-null,
but we’re at a point in RandBLAS’ code that would have written to obj.member if it were null.
There are two possibilities for what happens next.
If the documentation for
obj.memberstates an array length requirement purely in terms ofconstmembers, then we silently skip memory allocations that would overwriteobj.member. We’ll simply assume thatobj.memberhas the correct size.Under any other circumstances, RandBLAS raises an error.
In essence, the first situation has enough structure that the user could plausibly understand RandBLAS’ behavior, while the latter situation is too error-prone for RandBLAS to play a role in it.
Discussion
- Clarifications:
No RandBLAS datatypes use
newornew []in their constructors. Reference members of such datatypes are either null-initialized or initialized at user-provided values.Move-constructors are allowed to overwrite an object’s reference members with
nullptrif those references have been copied to a newly-created object.Users retain the ability to overwrite any RandBLAS object’s
own_membermember and its reference members at any time; no such members are declared as const.
We’re not totally satisfied with this document writ-large. It would probably be better if removed the commentary from the enumerations above and added lots of examples that refer to actual RandBLAS code. Alas, this will have to do for now. Questions about what specific parts of this policy mean or proposed revisions are welcome! Please get in touch with us on GitHub.