views:

281

answers:

2

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?

+7  A: 

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.

Evan Teran
Yes, I know, I actually did that, though I used placement new instead of std::allocator<T>::construct (which is probably not recommendable so I changed that now). However, it turns out that STLPort 4.x does not know about std::allocator<T>::construct either...
Kasper Peeters
If STLPort doesn't have `std::allocator<T>::construct` then it is broken, don't bother even using it. I can tell you for certain that 5.1.5 (the version I have installed does have it and works fine).
Evan Teran
I looked to satisfy my curiosity, STLPort 4.x **does** have a proper standards conformant `std::allocator`. In 4.6, the `construct` function is found on line 365 of `stlport/stl/_alloc.h`. If it isn't working, your install isn't correct.
Evan Teran
+1  A: 

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:

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.

Michael Burr
unfortunately it doesn't trace `construct` which is the function he was failing to use :-/
Evan Teran
That's true (I mentioned that shortcoming in my answer), and I was intending my answer to be more or less a side-bar to your answer that points out the problem directly. Lavavej posted the `mallocator` as a simple example of a custom allocator. I was proposing that it could also be used as an easy way to gain insight into how containers use allocators, but that there might need to be some minor modifications made to improve tracing for that purpose.
Michael Burr