I create a custom memory allocator like following:
class pool_allocator
{
// required methods
// ...
private:
boost::shared_ptr<MemoryChunks> m_t;
};
The purpose of this allocator is to share memory allocating by different container and only deallocate them when all container and deleted. therefore, I use boost::shared_ptr.
However after running it in VS2008, I detect a memory leak. I don't know why.
If I change boost::shared_ptr to MemoryChunks, the memory leak goes away.
Are you aware that allocators are treated as stateless in C++03? Try using your allocator in conjuntion with Boost.Containers (It was just accepted, but I think they are already part of Boost.Interprocess), which respects allocators. Not easy to say anything else without the definition for MemoryChunks.
Related
I need a custom allocator for STL vectors and maps so it "allocates" memory in preallocated memory block. I came across this piece of code which is in almost every allocator out there.
Allocator(const Allocator<U, growSize> &other)
{
if (!std::is_same<T, U>::value)
rebindAllocator = new std::allocator<T>();
}
Can somebody please explain what it does and why we need this interface to be implemented?
Big thanks in advance.
Full source code
Think of an allocator as a typed interface referencing some underlying untyped storage. Many allocators may reference the same storage.
Allocators are required to allow rebinding so that an allocator for T can be turned into an allocator for U referencing the same storage. Allocators are required to be copy constructible, and a copy of the allocator must reference the same storage. See cppreference.
This allocator implementation also is the storage. It derives from a memory pool. Therefore, it needs a way for a copied allocator to allocate and deallocate from the original storage, not its own. This is copyAllocator. For reasons which are not clear, it only does this on Windows.
Similarly, a rebound allocator needs to access the same storage. This allocator seems to violate that and use std::allocator. This means it is not fit for many STL use cases. std::map and other node-based containers will allocate with a rebound allocator, which means they won't use the memory pool.
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 have an array of (for example) uint8_ts.
Is std::unique_ptr the wrong tool to use to manage this object in memory?
For example,
std::unique_ptr<uint8_t> data(new uint8_t[100]);
Will this produce undefined behaviour?
I want a smart-pointer object to manage some allocated memory for me. std::vector isn't ideal, because it is a dynamic object. std::array is no good either, because the size of allocation is not known at compile time. I cannot use the [currently, 2016-03-06] experimental std::dynarray, as this is not yet available on Visual Studio 2013.
Unfortunately I have to conform to VS2013, because, rules.
The way you're using the unique_ptr will indeed result in undefined behavior because it'll delete the managed pointer, but you want it to be delete[]d instead. unique_ptr has a partial specialization for array types to handle such situations. What you need is
std::unique_ptr<uint8_t[]> data(new uint8_t[100]);
You can also use make_unique for this
auto data = std::make_unique<uint8_t[]>(100);
There is a subtle difference between the two, however. Using make_unique will zero initialize the array, while the first method won't.
Certainly unique_ptr as you've used it is incorrect because it will call delete rather than delete[] to deallocate the memory.
The normal solution to this situation is std::vector: It allocates and manages your memory as well as providing a fairly robust interface. You say that you don't want to use vector because True, but would be risky to expose that functionality to the user. from which I infer you're exposing the implementation detail of your container type to the interface of your class. That then is your real problem.
So use vector to manage the memory but don't expose vector directly in your class interface.
Sorry for the long title~
I have a simple allocator implemented on top of a memory pool whose deallocate() is empty. If a STL container is used with this allocator and the elements of the container are trivially destructible, can I avoid invoke the container's destructor altogether ?
The standard probably says no, I'm not sure though. IMO, if this behavior is allowed, STL containers couldn't get any resources other than memory allocated from their allocators, which would limit STL vendors too much. I'm never an expert on the standard, I'd be glad to be proven wrong.
However, if my simple allocator is used along with some actual implementation like libstdc++ or libc++, would the program leak memory or run into other problems ?
Instead of using try/catch blocks everytime I need to construct any objects after allocating a block of memory for them with an allocator I use internally in my container, I would like to use a class derived from std::auto_ptr (I have no c++11 here) with an overridden destructor, so that it could deallocate the pointed memory and release the pointer afterwards. Are there any disadvantages in doing this?
If you don't mind using boost and boost::shared_ptr<>, you can provide a custom deleter. See the top 2 answers to this question.