I recently started looking into allocators and the new pmr introduced in c++17.
Looking at the definition of std::pmr::new_delete_resouece on cppreference I read the following:
Returns a pointer to a memory_resource that uses the global operator new and operator delete to allocate memory.
That "global" is kinda confusing me. What does it mean? Does it just refers to the normal call of the operators like in
int* i = new int;
delete i;
thus allocating stuff on the heap, or does it refer to the static memory where global variables are allocated?
And what's the point in both cases to use such structure?
NicolBolas already gave a pretty clear answer, but since there appears to be some confusion in the comments regarding the "static storage duration" which I feels needs some clarity.
The function called
new_delete_resource()is defined, on cppreference, to have the following affect:(Emphasis mine)
What this means is that the
std::pmr::memory_resourceobject returned from this function has static-storage duration; not that calls ofallocate()operate on static storage duration.For example, this may be implemented as:
To be clear: the following code does not allocate memory with static-storage duration (by default[1]):
Rather, the above code is actually roughly equivalent to writing:
The "global operators" that the documentation refers to are the functions
::operator newand::operator delete.[1] By default, these operate on the heap -- though
::operator newand::operator deletecan be overridden by the user if they choose to define these. A program is legally allowed to define their own allocation mechanism if they choose -- at which point this may, in fact, be static-storage duration. However, such a point is more esoteric; as far as the standard is concerned, the storage duration of the pointer is dynamic -- and not explicitly static storage.So what's the point?
Aside from being a suitable and useful default for an allocator (e.g. the
default_resource), this also offers great composability with othermemory_resources. For example, apool_resourcemay use this as the upstreammemory_resourcefor when the pool runs out of allocations.Having a resource like this becomes really important for symmetry with
std::allocator<T>(which means a cheap upgrade path), and for enablingstd::pmr::polymorphic_allocatorto have a suitable default.Why
newanddelete?newanddeleteare built-in facilities in C++ -- so it's easy to use these and base it in terms of this. Since the global::operator newand::operator deletecan be overridden by custom definitions, this makes it a simple customization point that works seamlessly in any existing application. Additionally, it follows the existing pattern forstd::allocator<T>which usednewanddelete.If, instead, this were
std::malloc/std::free, or some other allocation function -- then old user code that previously defined custom hooks for::operator newwould cease to function correctly. This would lead the behavior of a container usingstd::allocator<T>to behave differently than a container usingstd::pmr::polymorphic_allocator<T>with astd::pmr::new_delete_resource-- which would be undesirable. (Note: the default resource is anew_delete_resource, which is what provides this symmetry by default).