I am looking to implement a (doubly) linked list which only calls placement new internally, directing all memory to a pool allocated with something like:
char *memPool = new char[4096]; // One-off normal 'new'
Initially I was going to implement my own class which takes a pointer to a (class managing a) pre-allocated memory pool. However I want to be sure first that I can't achieve the same outcome with std::list. In particular, the third section of David Rodríguez's answer to this SO question worries me.
It makes sense that std::list will have to call new and delete on its component nodes, but I want to modify this behaviour so that all the nodes to be allocated with placement new into my custom pool. Therefore my question is:
Is there a way to specify that a placement new std::list such as:
std::list<std::shared_ptr<Cls>> myList = new (pool.getFreeAddr()) list<Cls>;
should also allocate its nodes using a custom allocator, so that everything is stored strictly inside my own memory pool?
(Note: I am aware of the need to use custom allocation/deletion functions with the shared_ptrs if I want them in the custom memory pool too.)
You have to:
Write a class template MyAllocator that satisfies the Allocator requirements ([allocator.requirements] in the standard).
Use a std::list<T, MyAllocator<T> > in place of a std::list<T>.
If you need the type of your list to be specifically std::list<T> (for example because you want to call functions that accept a std::list<T> & and whose interface you can't change), then you're out of luck because the allocator type is part of the container type.
Be careful about the allocator requirements, they're strange. In particular you will need rebind for a list, and it's a bit tricksy.
Furthermore, in C++03 there's no guarantee that allocator instances are respected, only the allocator type, which in effect means that the pointer to the pool you're allocating from needs to be stored with static duration rather than as an instance variable. I think that was changed in C++11, but I might be wrong. It only really matters if you want to use multiple different pools in your program.
Related
I'm trying to design the internal mechanics of a simple embedded application. Chunks of data arrive on the network which need to be delivered to components determined by an addressing mechanism. Multiple components may subscribe to the same address. I want to design an architecture where incoming chunks are encapsulated into wrapper objects allocated from a memory pool. Each component might hold onto the wrappers (and the data inside them) as long as they need and it should be freed when all components let go of it. At that time it's returned to the pool and again ready to be allocated. The pool exhausting is not a concern.
I plan to use this memory pool implementation which satisfies Allocator. For the automatic destruction of wrapper objects I plan to use std::shared_ptr so when all components free the wrapper, it is automatically destroyed and the used memory returned to the pool.
What I don't see is how these two concepts can come together. If I allocate memory from the pool directly (by calling allocate()), it would give me a pointer to the block of data which is fine but then how will deallocate() be called automatically? Or do I need to use another container for my wrapper objects like std::list and pass it the memory pool allocator?
You can use std::shared_ptr with a custom allocator using std::allocate_shared. This is probably what you want anyway, since I'm assuming you want the control block (i.e. reference counts) to be allocated using the pool allocator as well.
When constructing an object using std::allocate_shared, a copy of the allocator is stored inside the shared_ptr, so the correct deallocate() will be called on destruction.
Note that you could also create your std::shared_ptr using a custom deleter, e.g.:
auto allocator = getAllocator<Foo>();
auto ptr = std::shared_ptr<Foo>(new(allocator.allocate()) Foo,
[&allocator](auto * ptr) { allocator.deallocate(ptr); });
However, as I mentioned that's probably not what you want, since space for the reference counts will not be allocated using your allocator object.
Btw, in case you're still "shopping around", here is another memory pool implementation which I quite like: foonathan::memory. It provides its own allocate_shared.
Suppose you developed an optimized custom allocator that you want to use with std::vector (for example, for small allocations the custom allocator gets memory from the stack instead of the heap, kind of like std::string's SSO; or it allocates big chunks of memory using e.g. VirtualAlloc on Windows, and then single allocations are carved from inside a chunk just increasing a pointer).
typedef std::vector<T, OptimizedAllocator<T>> OptimizedVector;
How to use it in a context where you are returning a vector from a function, like this?
OptimizedVector DoSomething()
{
OptimizedVector<int>::allocator_type alloc{};
OptimizedVector<int> v{alloc};
// Do stuff...
return v;
}
At the end of the function's scope, the allocator object is destroyed, so the returned vector could contain garbage, right?
An alternative might be to pass the allocator object as a reference to each function as an additional parameter, but that's kind of ugly...
Is there a way to safely "embed" the allocator object in the vector?
How do you solve this problem?
An allocator must be CopyConstructible without exceptions, and afterwards a1 == a2 must hold (meaning they share the same memory pool). I strongly suggest reading this page on the Allocator concept.
std::vector stores a copy of the allocator you give it.
So if you properly implement your allocator to be safe to copy, there will be no problem with your given code.
The allocator is kept by copy as defined by the standard:
n4140 §23.2.1 [container.requirements.general]/8
Unless otherwise specified, all containers defined in this clause
obtain memory using an allocator [...] A copy of this allocator is
used for any memory allocation performed [...]
vector is not "otherwise specified".
This also means that your allocator should support copying and probably be a handle for the real allocator if it needs state.
From here:
The container keeps an internal copy of alloc, which is used to allocate and deallocate storage for its elements, and to construct and destroy them (as specified by its allocator_traits).
So, if I'm not wrong, what you're asking for is the default.
I am using few library functions that return a pointer created either using malloc or new.
So, I have my own customer deallocator based on what type of allocation was used.
E.g
shared_ptr<int> ptr1(LibFunctA(), &MallocDeleter); //LibFunctA returns pointer created using malloc
shared_ptr<int> ptr2(LibFunctB(), &newDeleter); //LibFunctB returns pointer created using new
Now, I understand this is a very naive use of deallocator above but what other scenarios is it heavily used for ?
Also, how can one use a customer allocator ? I tried to assign a custom allocator as below but now how do I actually get it called ? Where does this kind of feature help ?
shared_ptr<int> ptr3(nullptr_t, &CustomDeleter, &CustomAllocator); //assume both functs are defined somewhere.
I don't see anything "naive" about using deleters that way. It is the main purpose of the feature after all; to destroy pointer objects that aren't allocated using the standard C++ methods.
Allocators are for when you need control of how the shared_ptr's control block of memory is allocated and deleted. For example, you might have a pool of memory that you want these things to come from, or if you're in a memory-limited situation where allocation of memory via new is simply not acceptable. And since the type of the control block is up to shared_ptr, there's no other way to be able to control how it is allocated except with some kind of allocator.
Custom deleters for shared_ptr are very useful for wrapping some (usually) C resource that you need to later call a freeing function on. For example, you might do something like:
shared_ptr<void> file(::CreateFileW(...), ::CloseHandle);
Examples like this abound in C libraries. This saves from having to manually free the resource later and take care of possible exceptions and other nasties.
I think the custom allocator will be used to allocate space for the "shared count" object, that stores a copy of the deallocator (deleter) and the reference counter.
As for what a custom deleter can be used for...
One use was already mentioned: make shared_ptr compatible with objects that must be deleted by some special function (like FILE which is deleted by fclose), without having to wrap it into a helper-class that takes care of the proper deletion.
Another use for a custom deleter is pools. The pool can hand out shared_ptr<T> that were initialized with a "special" deleter, which doesn't really delete anything, but returns the object to the pool instead.
And one other thing: the deleter is already necessary to implement some shared_ptr features. E.g. the type that's deleted is always fixed at creation time, and independent of the type of the shared_ptr that's being initialized.
Vou can create a shared_ptr<Base> by actually initializing it with a Derived. shared_ptr guarantees that when the object is deleted, it will be deleted as a Derived, even if Base does not have a virtual dtor. To make this possible, shared_ptr already has to store some information about how the object shall be deleted. So allowing the user to specify a completely custom deleter doesn't cost anything (in terms of runtime performance), and doesn't require much additional code either.
There are probably dozens of other scenarios where one can make good use of the custom deleter, that's just what I have come up with so far.
I couldn't find an exact answer to this question and hence posting here.
When I think of vector, it needs to build objects in a contiguous memory location. This means that vector keeps memory allocated and have to do an in-place construction (=placement new) of objects being pushed into it. Is this a valid assumption? Also, does this mean the container is manually invoking the destructor rather than calling delete? Are there any other assumptions that I am missing here? Does this mean I can assume that even a custom written new for the object may not be invoked if I chose to write?
Also it makes sense for a list to use a new and delete as we don't need the continuous memory guarantee. So, is this kind of behavior is what drives how allocators behave? Please help.
Thanks
This means that vector keeps memory allocated and have to do an in-place construction (=placement new) of objects being pushed into it. Is this a valid assumption?
Yes
Also, does this mean the container is manually invoking the destructor rather than calling delete?
Yes
Are there any other assumptions that I am missing here? Does this mean I can assume that even a custom written new for the object may not be invoked if I chose to write?
Yes. Consider that even in linked lists, the container will not allocate an instance of your type, but rather a templated structure that contains a subobject of the type. For a linked list that will be some complex type containing at least two pointers (both links) and a subobject of your type. The actual type that is allocated is that node, not your type.
Also it makes sense for a list to use a new and delete as we don't need the continuous memory guarantee.
It does, but it does not new/delete objects of your type.
So, is this kind of behavior is what drives how allocators behave?
I don't really understand this part of the question. Allocators are classes that have a set of constraints defined in the standard, that include both the interface (allocate, deallocate...) and semantics (the meaning of == is that memory allocated with one can be deallocated with the other, any other state in the class is irrelevant).
Allocators can be created and passed onto containers for different reasons, including efficiency (if you are only allocating a type of object, then you might be able to implement small block allocators slightly more efficient than malloc --or not, depends on the situation).
Side note on placement new
I have always found interesting that placement new is a term that seems to have two separate meanings. On the one side is the only way of constructing an object in-place. But it seems to also have a complete different meaning: construct this object acquiring memory from a custom allocator.
In fact there is a single meaning of placement new that has nothing to do with constructing in-place. The first is just a case of the second, where the allocator is provided by the implementation (compiler) as defined in 18.4.1.3 and cannot be overloaded. That particular version of the overloaded allocator does absolutely nothing but return the argument (void*) so that the new-expression can pass it into the constructor and construct the object on the memory (not) allocated by the placement new version that was called.
You're very close to being perfectly correct. The way that the vector (and all the other standard containers) do their allocation is by using the std::allocator class, which has support for constructing and destructing objects at particular locations. Internally, this uses placement new and explicit destructor calls to set up and destroy objects.
The reason I say "very close to being perfectly correct" is that it's possible to customize how STL containers get their memory by providing a new allocator as a template argument in lieu of the default. This means that in theory it should be possible to have STL containers construct and destruct objects in different ways, though by default they will use the standard placement new.
I need to create a pool of objects to eliminate dynamic allocations. Is it efficient to use std::stack to contain pointers of allocated objects?
I suspect every time I push the released object back to stack a new stack element will be dynamically allocated. Am I right? Should I use std::vector to make sure nothing new is allocated?
Whether a stack is suited for your particular purpose or not is an issue I will not deal with. Now, if you are concerned about the number of allocations, the default internal container for a std::stack is an std::deque<>. It will not need to allocate new memory for the stack in each push (as long as it has space) and when it allocates it does not need to relocate all existing elements as an std::vector<> would.
You can tell the stack to use an std::vector<> as underlying container with the second template argument:
std::stack< int, std::vector<int> > vector_stack;
STL containers of pointers don't do anything with the objects they point to, that's up to you, so you are responsible for not leaking any memory etc. Have a look at Boost Pointer Container Library or try storing the actual objects, you will save yourself hassle in the long run.
If you want to reduce the amount of dynamic allocations made by the container and you know roughly how many objects you need to store, you can use vector's 'reserve()' method, which will preallocate the memory you request in one shot.
You can also specify the number of records you want in the constructor, but this way will create x objects for you and then store them, which might not be want you want.
If, for some technical reason dynamic allocation is out completely, you might want to try using boost::pool as your allocator, (as you know you can specify a different std library memory allocator if you don't want to use the default one).
That said, when I tested it, the default one was always faster, at least with g++ so it may not be worth the effort. Make sure you profile it rather than assume you can out code the standards commitee!
Doing ANY allocs during a free is WRONG due to nothrow-guarantees. If you have to do an alloc to do a free and the alloc throws where do you put the pointer? You either quietly capture the exception and leak or propagate the exception. Propagating the exception means objects that use your YourObject cant be put in STL containers. And leaking is, well, leaking. In either case you have violated the rules.
But what data structure to use depends on your object lifetime control idiom.
Is the idiom an object pool to be used with a factory method(s) and freeInstance
YourObject* pO = YourObject::getInstance(... reinitialize parameters ...);
......object public lifetime....
pO->freeInstance();
or a memory pool to be used with a class specific operator new/operator delete (or an allocator)?
YourObject::operator new(size_t);
......object public lifetime....
delete pO;
If it is an object pool and you have an idea about the number of YourObject*'s use vector in released code and deque or preferably a circular buffer (as deque has no reserve so you have to add this where as a dynamically self sizing circular buffer is precisely what you want) in debug code and reserve the approximate number. Allocate LIFO in release and FIFO in debug so you have history in debug.
In the path where there are no free objects, remember to do the reserve(nMade+1) on the YourObject* collection before you dynamically create an object.
(The reason for this reserve is two fold. First, it must be done at createInstance time Second, it simplifies the code. For otherwise you have the possibility of throwing a std::badalloc in freeInstance which may make destructor guarantees hard to guarantee. OUCH! e.g. - class Y has an YourObject* in it and does a freeInstance for that YourObject* in its destructor - if you don't reserve the space for the YourObject* when you make it where do you store that pointer at freeInstance time? If you reserve the space afterwards in getInstance then you have to catch the std::badalloc for the reserve, release the just made YourObject, and rethrow.)
If it is a memory pool then in the memory blocks use an intrusive singly linked list in release and doubly linked list in debug (I am assuming that sizeof(YourObject)>=2*sizeof(void*)) BTW there are a lot of MemoryPool implementations out there. Again allocate LIFO in release and FIFO in debug so you have history in debug.
BTW if you use the factory idiom don't skip on the overloaded getIntances() and add reinit methods. That just opens up the possibility of leaving out a reinit call. The getInstance methods are your "constructors" in the sense that it is they that get the object to the state that you want. Note that in the object pool case you need a freeInstance which may have to do "destructor like" things to the object.
In this case it makes some sense to speak of "public class invariants" and "private class invariants" - the object sits in a limbo state where public class invariants may NOT be satisfied while in the free pool. Its a YourObject as fas as a YourObject is concerned but all of the public class invariants may not be satisfied. It is the job of YourObject::getInstance to both get an instance AND ensure that its public invariants are satisfied. In a complementary fashion freeInstance releases resources that may have been acquired by getInstance to ensure the "public class invariants" were satisfied may be released during the objects "idle time" on the free list.
LIFO in release also has the SIGNIFICANT benefit of caching the last used objects/blocks where as FIFO is guaranteed not to cache if there are a sufficiently large number of objects/blocks - or even page if the number is larger! But you probably already realized this as you decided to use a stack.
strong text