I'm working on the runtime library for a dynamic language, and more specifically on its memory allocation.
I will use garbage collection, but I thought it would be nice to allow the user to use its own memory allocator if it needs to. However, after looking at the standard c++ allocator interface, I didn't seen any way to have a generic allocator (except by templating on char, but it seems hacky).
Is it a good idea to use the standard allocator interface ?
If it is, what would be a possible design for allocating multiple types ?
Note : My library use C++11, so I'm talking about the 'new' allocator interface.
As #Cubbi said, look at allocator::rebind. The actual type argument to an allocator is pretty-much irrelevant. Standard containers use allocator::rebind to change to the type that they actually need. In particular, associative containers need to allocate nodes that hold their own data as well as the data objects that the container nominally holds. So allocator::rebind is used to get an allocator<Node<T>> from an allocator<T>.
Depends on whether you want compile-time or run-time polymorphism. The standard allocator is good for the former case. For the latter, you can do something like:
class Allocator {
public:
virtual void* allocate(std::size_t size) = 0;
virtual void deallocate(void* p) = 0;
}
The users would be able to customize the allocator via the virtual functions.
Related
I'm writing some code that handles cryptographic secrets, and I've created a custom ZeroedMemory implementation of std::pmr::memory_resource which handles sanitizes memory on deallocation and encapsulates using the magic you have to use to prevent optimizing compilers from eliding away the operation. The idea was to avoid specializing std::array, because the lack of a virtual destructor means that destruction after type erasure would cause memory to be freed without being sanitized.
Unfortunately, I came to realize afterwards that std::array isn't an AllocatorAwareContainer. My std::pmr::polymorphic_allocator approach was a bit misguided, since obviously there's no room in an std::array to store a pointer to a specific allocator instance. Still, I can't fathom why allocators for which std::allocator_traits<A>::is_always_equal::value == true wouldn't be allowed, and I could easily re-implement my solution as a generic Allocator instead of the easier-to-use std::pmr::memory_resource...
Now, I could normally just use an std::pmr::vector instead, but one of the nice features of std::array is that the length of the array is part of the type. If I'm dealing with a 32-byte key, for example, I don't have to do runtime checks to be sure that the std::array<uint8_t, 32> parameter someone passed to my function is, in fact, the right length. In fact, those cast down nicely to a const std::span<uint8_t, 32>, which vastly simplifies writing functions that need to interoperate with C code because they enable me to handle arbitrary memory blocks from any source basically for free.
Ironically, std::tuple takes allocators... but I shudder to imagine the typedef needed to handle a 32-byte std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, ...>.
So: is there any standard-ish type that holds a fixed number of homogenously-typed items, a la std::array, but is allocator aware (and preferably stores the items in a continguous region, so it can be down-cast to an std::span)?
You need cooperation from both the compiler and the OS in order for such a scheme to work. P1315 is a proposal to address the compiler/language side of things. As for the OS, you have to make sure that the memory was never paged out to disk, etc. in order for this to truly zero memory.
This sounds like a XY problem. You seem to be misusing allocators. Allocators are used to handle runtime memory allocation and deallocation, not to hook stack memory. What you are trying to do — zeroing the memory after using — should really be done with a destructor. You may want to write a class Key for this:
class Key {
public:
// ...
~Key()
{
secure_clear(*this); // for illustration
}
// ...
private:
std::array<std::uint8_t, 32> key;
};
You can easily implement iterator and span support. And you don't need to play with allocators.
If you want to reduce boilerplate code and make the new class automatically iterator / span friendly, use inheritance:
class Key :public std::array<std::uint8_t, 32> {
public:
// ...
~Key()
{
secure_clear(*this); // for illustration
}
// ...
};
After I am studying about allocator for a few days by reading some articles
(cppreference and Are we out of memory) ,
I am confused about how to control a data-structure to allocate memory in a certain way.
I am quite sure I misunderstand something,
so I will divide the rest of question into many parts to make my mistake easier to be refered.
Here is what I (mis)understand :-
Snippet
Suppose that B::generateCs() is a function that generates a list of C from a list of CPrototype.
The B::generateCs() is used in B() constructor:-
class C {/*some trivial code*/};
class CPrototype {/*some trivial code*/};
class B {
public:
std::vector<C> generateCs() {
std::vector<CPrototype> prototypes = getPrototypes();
std::vector<C> result; //#X
for(std::size_t n=0; n < prototypes.size(); n++) {
//construct real object (CPrototype->C)
result.push_back( makeItBorn(prototypes[n]) );
}
return result;
}
std::vector<C> bField; //#Y
B() {
this->bField = generateCs(); //#Y ; "generateCs()" is called only here
}
//.... other function, e.g. "makeItBorn()" and "getPrototypes()"
};
From the above code, std::vector<C> currently uses a generic default std::allocator.
For simplicity, from now on, let's say there are only 2 allocators (beside the std::allocator) ,
which I may code it myself or modify from somewhere
:-
HeapAllocator
StackAllocator
Part 1 (#X)
This snippet can be improved using a specific type allocator.
It can be improved in 2 locations. (#X and #Y)
std::vector<C> at line #X seems to be a stack variable,
so I should use stack allocator :-
std::vector<C,StackAllocator> result; //#X
This tends to yield a performance gain. (#X is finished.)
Part 2 (#Y)
Next, the harder part is in B() constructor. (#Y)
It would be nice if the variable bField has an appropriate allocation protocol.
Just coding the caller to use allocator explicitly can't achieve it,
because the caller of constructor can only do as best as :-
std::allocator<B> bAllo;
B* b = bAllo.allocate(1);
which does not have any impact on allocation protocol of bField.
Thus, it is duty of constructor itself to pick a correct allocation protocol.
Part 3
I can't know whether an instance of B will be constructed as a heap variable or a stack variable.
It is matter because this information is importance for picking a correct allocator/protocol.
If I know which one it is (heap or stack), I can change declaration of bField to be:-
std::vector<C,StackAllocator> bField; //.... or ....
std::vector<C,HeapAllocator> bField;
Unfortunately, with the limited information (I don't know which it will be heap/stack, it can be both),
this path (using std::vector) leads to the dead end.
Part 4
Therefore, the better way is passing allocator into constructor:-
MyVector<C> bField; //create my own "MyVector" that act almost like "std::vector"
B(Allocator* allo) {
this->bField.setAllocationProtocol(allo); //<-- run-time flexibility
this->bField = generateCs();
}
It is tedious because callers have to pass an allocator as an additional parameter,
but there are no other ways.
Moreover, it is the only practical way to gain the below data-coherence advantage when there are many callers, each one use its own memory chunk:-
class System1 {
Allocator* heapForSystem1;
void test(){
B b=B(heapForSystem1);
}
};
class System2 {
Allocator* heapForSystem2;
void test(){
B b=B(heapForSystem2);
}
};
Question
Where did I start to go wrong, how?
How can I improve the snippet to use appropriate allocator (#X and #Y)?
When should I pass allocator as a parameter?
It is hard to find a practical example about using allocator.
Edit (reply Walter)
... using another than std:allocator<> is only rarely recommendable.
For me, it is the core of Walter's answer.
It would be a valuable knowledge if it is reliable.
1. Are there any book/link/reference/evidence that support it?
The list doesn't support the claim. (It actually supports the opposite a little.)
Is it from personal experience?
2. The answer somehow contradict with many sources. Please defense.
There are many sources that recommend not to use std:allocator<>.
Are we out of memory :
Can't answer "How much memory are you using for subsystem X?" is a guilty.
Custom C++ allocators suitable for video games
It implies that custom allocator is a must for console games.
# section "Why replace the default allocator?"
Memory Management part 1 of 3
without custom allocator = "every now and then there’s a little lag (in game)"
More specifically, are they just a "hype" that rarely worth using in real world?
Another small question :-
Can the claim be expanded to "Most quality games rarely use custom allocator"?
3. If I am in such rare situation, I have to pay the cost, right?
There are only 2 good ways:-
passing allocator as template argument, or
as a function's (including constructor) parameter
(another bad approach is to create some global flag about what protocol to use)
Is it correct?
In C++, the allocator used for the standard containers is tied to the container type (but see below). Thus, if you want to control the allocation behaviour of your class (including its container members), the allocator must be part of the type, i.e. you must pass it as a template parameter:
template<template <typename T> Allocator>
class B
{
public:
using allocator = Allocator<C>
using fieldcontainer = std::vector<C,allocator>;
B(allocator alloc=allocator{})
: bFields(create_fields(alloc)) {}
private:
const fieldcontainer bFields;
static fieldcontainer create_fields(allocator);
};
Note, however, that there is experimental polymorphic allocator support, which allows you change the allocator behaviour independently of the type. This is certainly preferable to designing your own MyVector<> template.
Note that using another than std::allocator<> is only recommendable if there is a good reason. Possible cases are as follows.
A stack allocator may be preferred for small objects that are frequently allocated and de-allocated, but even the heap allocator may not be less efficient.
An allocator that provides memory aligned to, say, 64bytes (suitable for aligned loading into AVX registers).
A cache-aligned allocator is useful to avoid false sharing in multi-threaded situations.
An allocator could avoid default initialising trivially constructible objects to enhance performance in multi-threaded settings.
note added in response to additional questions.
The article Are we out of memory dates from 2008 and doesn't apply to contemporary C++ practice (using the C++11 standard or later), when memory management using std containers and smart pointers (std::unique_ptr and std::shared_ptr) avoids memory leaks, which are the main source of increasing memory demand in poorly written code.
When writing code for certain specific applications, there may well be good reasons to use a custom allocator -- and the C++ standard library supports this, so this is a legitimate and appropriate approach. The good reasons include those listed already above, in particular when high performance is required in a multi-threaded environment or to be achieved via SIMD instructions.
If memory is very limited (as it may be on some game consoles), a custom allocator cannot really magically increase the amount of memory. So in this case the usage of the allocator, not the allocator itself, is most critical. A custom allocator may help reducing memory fragmentation, though.
It sounds like you are misunderstanding what a stack allocator is. A stack allocator is just an allocator that uses a stack, the data structure. A stack allocator can manage memory that is either allocated on the stack or the heap. It is dangerous to use if you don't know what you are doing as a stack allocator deallocates all the memory past the specified pointer when deallocate is called. You can use a stack allocator for when the most recently initialized element in a data structure is always the next one destroyed (or if you end up destroying them all at once in the end).
You can look at some of the std collections to see how they allow programmers to supply a specified allocator such as std::vector. They use an optional template argument so the user can choose the allocator class. It also allows you to pass the allocator in as an instance if you want to. If you don't, it instantiates one with the default constructor. If you don't choose an allocator class, then it uses the default allocater which just uses the heap. You could do the same.
template<typename C, typename Allocator = std::allocator<C> >
class B {
vector<C, Allocator> bField;
void generateCs() {
std::vector<CPrototype> prototypes = getPrototypes();
for(std::size_t n=0; n < prototypes.size(); n++) {
//construct real object (CPrototype->C)
bField.push_back( makeItBorn(prototypes[n]) );
}
}
B(const Allocator& allo = Allocator()) : bField(allo) {
generateCs();
}
}
This allows the user to have control over allocation when they want to, but they also ignore it if they don't care
From what I read in http://en.cppreference.com/w/cpp/memory/allocator , most features of the allocators are now going to be deprecated. The question is, how is one supposed to use allocators in new code? What is the "right" way now?
From what I deduce in the documentation, construct is part of the allocator traits, rather than the allocator itself.
I am building a custom container, here it is a very simple version of the constructor, is this a good usage of the new design?
container::container(std::size_t size, T const& value, Allocator const& allocator) : allocator_(allocator){
data_ = std::allocator_traits<Alloc>::allocate(allocator_, size);
for(auto ptr = data_; ptr != data_ + size; ++ptr){
std::allocator_traits<Allocator>::construct(allocator_, ptr, value)
}
}
I tried to use an algorithm (like std::for_each) in the loop but I didn't manage to use one without taking addresses (operator&).
Where can I find a complete example of a modern allocator?
After some tweaking, I found a way to use an algorithm instead of the the raw loop (to which an execution policy can be passed). I am not very sure, but it could be this:
data_ = std::allocator_traits<Allocator>::allocate(allocator_, size);
std::for_each([policy? deduced from allocator?,]
boost::make_counting_iterator(data_),
boost::make_counting_iterator(data_ + size),
[&](auto ptr){std::allocator_traits<Allocator>::construct(allocator_, ptr, value);}
);
Yes, the current approach is through std::allocator_traits. You'll be able to support the "minimal allocator interface" that way.
http://en.cppreference.com/w/cpp/concept/Allocator
Some requirements are optional: the template std::allocator_traits supplies the default implementations for all optional requirements, and all standard library containers and other allocator-aware classes access the allocator through std::allocator_traits, not directly.
If you observe the std::allocator_traits member functions and typedefs, you'll see they're detecting the presence of appropriate function/types and dispatching through them if they can.
The deprecation and potential future removal will change nothing if you're already using std::allocator_traits since it only applies to std::allocator and their member functions/typedefs.
Now, if you ask me, there's nothing wrong with for-loops, and using std::for_each gains you nothing. There are several uninitialized_* functions, but they use placement new directly. If you really care you can extract this code to a separate construct_range function.
There's also an exception safety issue - in case one of the constructors throws, you need to destroy the earlier elements in order to satisfy the strong exception guarantee and free the memory too (destructor won't get called in case constructor throws)
I am trying to use boost::singleton_pool to create a large number of objects of a type 'Order' in a highly performance critical multithreaded application. Looking at the documentation, this is what I should be doing,
struct OrderTag{};
typedef boost::singleton_pool<OrderTag, sizeof(Order)> OrderPool;
boost::singleton_pool has a static member function malloc which returns pointer of the void*, but I need to create objects of the type Order in OrderPool by making calls to its constructor. Shall I be using boost::pool_allocator along with singleton_pool to do so?
Thanks.
In short: no. boost::pool_allocator implementation itself uses boost::singleton_pool and provides interface like std::allocator so you can use it with STL containers (but not only STL and not only containers) like vector, list etc. The UserAllocator concept is not something like boost::pool_allocator but it's a thing that controls memory management at the lowest level. For example I wrote UserAllocator that allocates memory via mmap() function and not uses heap at all.
So to create objects of a type 'Order' you should use boost::pool_allocator or boost::fast_pool_allocator. In your case it is not necessary to use boost::singleton_pool directly.
You can use singleton_pool with placement new like this:
Order* p = new (OrderPool.malloc()) Order(/* add ctor parameters if any*/);
or use boost::object_pool<Order>
I am trying to write a container class which uses STL allocators. What I currently do is to have a private member
std::allocator<T> alloc_;
(this will later be templated so that the user can pick a different allocator) and then call
T* ptr = alloc_.allocate(1,0);
to get a pointer to a newly allocated 'T' object (and used alloc_.construct to call the constructor; see the answer below). This works with the GNU C++ library.
However, with STLPort on Solaris, this fails to do the right thing and leads to all sorts of bizarre memory corruption errors. If I instead do
std::allocator_interface<std::allocator<T> > alloc_;
then it is all working as it should.
What is the correct way to use the stl::allocator? The STLPort/Solaris version fails to compile with g++, but is g++ right?
You need to both allocate and construct with the allocator. Something like this:
T* ptr = alloc_.allocate(1,0);
alloc_.construct(ptr, value);
Lots of things are downright broken if you don't start with a properly constructed object. Imagine a std::string being allocated but not constructed. When you try to assign to it, it will first try to cleanup its old contents by freeing some data, which will of course be garbage values from the heap and crash.
Something you might want to do is have your own custom allocator that you can use to see how the standard containers interact wit allocators. Stephan T. Lavavej posted a nice, simple one called the mallocator. Drop it into a test program that uses various STL containers and you can easily see how the allocator is used by the standard containers:
http://blogs.msdn.com/vcblog/archive/2008/08/28/the-mallocator.aspx
Not all of the interface functions in the mallocator (such as construct() and destroy()) are instrumented with trace output, so you might want to drop trace statements in there to more easily see how the standard containers might use those functions without resorting to a debugger.
That should give you a good idea of how your containers might be expected to use a custom allocator.