The standard C++17 include a new namespace pmr including a set of classes grouped under the name of memory_resource.
After a search on internet, I found very few vulgarized information about it, the direct consequence is this question:
What are the main ideas behind pmr and especially pmr::memory_resource?
Detailing a bit more the question, some of the question marks in my head are:
What does it bring new, or what were the limitations it solve?
What is the difference with allocator?
Does polymorphic mean it is possible to select runtime the allocator provided to a container constructor? (e.g. for testing purpose)
Does it helps for implementing memory pool, or other memory management schemes?
Context:
In the intend of creating a memory pool allocator, I found information about this namespace. Reading names like pool_options or polymorphic_allocator raised my attention.
Related questions:
polymorphic_allocator: when and why should I use it?
A polymorphic_allocator is intended to let you have an allocator whose behavior is dynamically determined at runtime.
The only way to create a polymorphic_allocator is:
Default constructed, in which case it uses std::pmr::get_default_resource() return value, which is a memory_resource*.
Pass it a memory_resource*.
copy from another polymorphic_allocator.
So the point of customization for a polymorphic_allocator is creating a class that inherits from memory_resource and implementing its methods, or using one of the pre-declared memory_resources that are defined in std::pmr: (un)synchronized_pool_resource and monotonic_buffer_resource as types, or std::pmr::new_delete_resource() / std::pmr::null_memory_resource().
Suppose you want a your memory to be allocated using a strategy different than the 5 provided in std::pmr. Then you make a class that inherits from std::pmr::memory_resource, and pass it to a container which uses a polymorphic_allocator.
Related
Lets say I have a class Obj, and instances of them are created at run time, can I store them without new like this?
Obj my_obj;
std::vector<Obj> my_vec;
my_vec.push_back(my_obj);
Or do I have to use new?
std::vector<Obj*> my_vec;
my_vec.push_back(new Obj);
And what if I have pointers inside of my class Obj? Also, what if use the second option, do I have to clean up everything?
The question is related to heap allocated objects vs. stack objects.
There are already a few good resources on that in Stackoverflow:
Stack Memory vs Heap Memory
Stack vs Heap C++
C++ stack vs heap allocation
Why should I use a pointer rather than the object itself?
(you may want to look at all the above, each has its own angle).
But, your question is specifically about a container holding objects or pointers to objects. For this there are a few other resources:
Should I store entire objects, or pointers to objects in containers?
Is it better to save object pointer in STL container rather than object itself?
Let me summarize shortly:
Usually working with values and not pointers should be your preferred option. They are much easier to maintain and less bug-prone. Before C++11 performance considerations could be a reason for considering working with container of pointers, but since move semantics came in C++11, if you design your code properly, working with containers of values should not be costly.
Another reason for working with pointers might be polymorphism. You want your container to hold and manage different types which share the same base class. Though it seems that a container of pointers should be the solution in such a case, which is used in many examples for polymorphism in C++, this still should not be your preferred choice. The first alternative for raw pointers should be holding unique_ptr which is a smart pointer type introduced in the C++ standard library in C++11.
The other option is to model the data that you want to manage withing a class that would hide and manage your polymorphism without exposing it to the container or to the user. Let's take an example: suppose you want to manage a container of Command objects, where Command is a base class for many different actual commands. Instead of having a container of Command* or unique_ptr<Command>, rename Command to be CommandBase, then hold (wrap, hide) unique_ptr<CommandBase> inside class Command and hold in your container objects of type Command.
Another alternative would be to avoid inheritance altogether. So for different callables (our Command example) you can just use std::function.
You can also use std::variant to manage the different types (e.g. using Shape = std::variant<Circle, Triangle>;).
Hiding the fact that you are using polymorphism, or avoiding polymorphism altogether, can become quite useful in your API, with the benefits of being able to preserve proper value semantics.
More on value semantics and its benefits can be found in CppCon 2022 talk by Klaus Iglberger: Back to Basics: Cpp Value Semantics and in C++Now 2022 talk by Dave Abrahams: A Future of Value Semantics and Generic Programming, Part 1 and Part 2. The original talk on the subject, by Sean Parent: Value Semantics and Concepts-based Polymorphism, from C++Now 2012.
You can also read about value semantics in the following links:
C++ classes as value types a Microsoft blog post
Reference and Value Semantics in ISO-CPP FAQ
Value Semantics and Polymorphism a blog post by Dean Berris
A pointer to a good doc, paper, book, etc. on how to do this and the range of possibilities one can use would be best here.
If one can, can one add a flag or data member to such an extended control block? can one override the control block destructor? deleter? etc.
If so how, with a sample piece of code showing how would be the ultimate answer in some ways :)
The control block is an implementation detail of shared_ptr. The only access you have to it is via the interfaces that the type gives you. Which at present consists entirely of being able to decide where its storage comes from. Even if you provide an allocator to the shared_ptr constructor, the standard doesn't require that shared_ptr will even use that allocator to construct/destroy the control block object, only to allocate and free the storage for it.
I'm looking into using mbed's MemoryPool API, however it seems to be oriented for simple POD types.
Inspecting the source of MemoryPool.h seems to show that it's just taking memory blocks and presenting as is (or zeroing the block if using calloc) and not doing placement new. I tried to follow the implementation, but got a bit lost in the syscall/weak-link maze.
My question: Is this MemoryPool implementation usable with non-trivial C++ classes? That is, if I make an allocation request, will the object constructor be called? Or do I need to create an adapted MemoryPool to perform placement new operations (and the corresponding destructor calls) in order to obtain properly initialized and constructed objects?
I've opened an issue over at Github - https://github.com/ARMmbed/mbed-os/issues/5891
What has been reported so far reinforces what #Pharap has said in their answer.
if I make an allocation request, will the object constructor be called?
It would seem not.
Although I cannot find the source code for the osMemoryPoolAlloc function, there are a few other giveaways.
Firstly as you mentioned, calling memset(item, 0, sizeof(T)); as the code does in calloc does indeed violate safe construction and destruction.
Secondly, the fact that the result of osMemoryPoolAlloc is being cast to (T*) implies that it returns a void * and knows nothing about the type it's allocating memory for other than perhaps its size.
do I need to create an adapted MemoryPool to perform placement new operations (and the corresponding destructor calls) in order to obtain properly initialized and constructed objects?
Yes, you would.
But as #Daniel Langr mentions, there could potentially be alignment issues involved.
For what it's worth there's a comment at the bottom of the code that says:
/* osMemoryPoolNew requires that pool block size is a multiple of 4 bytes. */
and I believe most arm devices are 32-bit so I would assume it's probably safe to use placement new to create a type that has an alignment of 4 (which you can check with alignof.
However, my advice is to raise an issue about this over on the github page.
It seems that the code is not sufficiently documented, so without intimate knowledge of the code it would be hard to give a straight answer to your second question.
(Note that if the memory returned is suitable aligned then you could create a simple wrapper template class that adheres to the rules of an allocator. This would permit use with allocator-enabled containers, though they would be limited in size as a result.)
I'm wrestling with some pain being caused by std::allocator_traits::construct. In order for a container to be a "conforming" user of the allocator concept, it needs to use construct rather than placement new to construct objects. This is very sticky for me. Currently I have a class (class A) that is designed to be allocator aware, and at some point it needs to create another instance of some other class (class B) in allocated memory. The problem is that class B implements the construction of the new object. If I could use placement new, this wouldn't be an issue: A would handle allocation, pass B the memory address, and B would construct into that. But since the construction needs to be performed via construct, I need to inject the allocator type into B, templating it, which creates a huge mess.
It's bad enough that I am seriously considering just using placement new, and static asserting that my instance of the allocator does not have a construct method (note that the static construct function calls the instance method if it exists, otherwise it calls placement new). I have never felt the tiniest urge to write a construct method for an allocator. The cost of making this part of the allocator concept seems very high to me; construction has gotten entangled with allocation, where allocators were supposed to help separate them. What justifies the existence of construct/destruct? Insight into the design decision, examples of real (not toy) use cases, or thoughts on the gravity of electing to simply use placement new appreciated.
There is a similar question; std::allocator construct/destroy vs. placement new/p->~T(). It was asked quite a long time ago, and I don't find the answer accepted there as sufficient. Logging is a bit trite as a use case, and even then: why is the allocator logging the actual construction of objects? It can log allocations and deallocations in allocate and deallocate, it doesn't answer the question in the sense of: why was construction made a province of the allocator in the first place? I'm hoping to find a better answer; it's been quite a few years and much about allocators has changed since then (e.g. allocators being stateful since 11).
A few points:
There really isn't a std container concept. The container requirements tables in the standard are there to document the containers specified by the standard.
If you have a container that wants to interact with std::allocator_traits<Alloc>, all you have to do is assume that Alloc conforms to the minimum C++11 allocator requirements and interact with it via std::allocator_traits<Alloc>.
You are not required to call std::allocator_traits<Alloc>::construct.
You are forbidden from calling Alloc::construct because it may not exist.
The standard-specified containers are required to call std::allocator_traits<Alloc>::construct only for container::value_type, and are forbidden from using std::allocator_traits<Alloc>::construct on any other types the container may need to construct (e.g. internal nodes).
Why was construct included in the "allocator concept" way back in C++98?
Probably because the committee at the time felt that this would ease dealing with x86 near and far pointers -- a problem that no longer exists today.
That being said, std::scoped_allocator_adaptor is a modern real-world example of an allocator that customizes both construct and destroy. For the detailed specification of those customizations I point you towards the latest C++1z working draft, N4567. The spec is not simple, and that is why I'm not attempting to reproduce it here.
Would it be possible in C++ to create a custom allocator that works simply like this:
{
// Limit memory to 1024 KB
ScopedMemoryPool memoryPool(1024 * 1024);
// From here on all heap allocations ('new', 'malloc', ...) take memory from the pool.
// If the pool is depleted these calls result in an exception being thrown.
// Examples:
std::vector<int> integers(10);
int a * = new int [10];
}
I couldn't find something like this in the boost libraries, or anywhere else.
Is there a fundamental problem that makes this impossible?
You would need to create a custom allocator that you pass in as a template param to vector. This custom allocator would essentially wrap the access to your pool and do whatever size validations that it wants.
Yes you can make such a construct, it's used in many games, but you'll basically need to implement your own containers and call memory allocation methods of that pool that you've created.
You could also experiment with writing a custom allocator for the STL containers, although it seems that that sort of work is generally advised against. (I've done it before and it was tedious, but I don't remember any specific problems.)
Mind- writing your own memory allocator is not for the faint of heart. You could take a look at Doug Lea's malloc, which provides "memory spaces", which you could use in your scoping construct somehow.
I will answer a different question. Look at 'efficient c++' book. One of the things they discuss is implementing this kind of thing. That was for a web server
For this particular thing you can either mess at the c++ layer by overriding new and supplying custom allocators to the STL.
Or you can mess at the malloc level, start with a custom malloc and work from there (like dmalloc)
Is there a fundamental problem that makes this impossible?
Arguing about program behavior would become fundamentally impossible. All sorts of weird issues will come up. Certain sections of the code may or may not execute though this will seeminly have no effect on the next sections which may work un-hindered. Certain sections may always fail. Dealing with the standard-library or any other third party library will become extremely difficult. There may be fragmentations at run-time at times and at times not.
If intent is that all allocations within that scope occur with that allocator object, then it's essentially a thread-local variable.
So, there will be multithreading issues if you use a static or global variable to implement it. Otherwise, not a bad workaround for the statelessness of allocators.
(Of course, you'll need to pass a second template argument eg vector< int, UseScopedPool >.)