Custom Allocator Question - Advanced.

J

joe

I have written a custom std allocator which follows the example in
Stroustrup's book.

I'm seeing a behavior I don't understand.

My allocate method within the allocator looks like the following:
(FooAllocator<T>)

pointer allocate(size_type cnt, typename
std::allocator<void>::const_pointer hint = 0)
{
pointer p = reinterpret_cast<pointer> (new char[sizeof(T)*cnt]);
std::cout<<"MEMORY ADDRESS: "<<p<<std::endl; //FIRST PRINT-OUT!
return p;
}

Then I have a regular container in my main:
int main()
{
typedef std::multiset<Foo,less<Foo>,FooAllocator<Foo> > MYSET;

MYSET mine;

MYSET::iterator iter = mine.insert(Foo());
std::cout<<"ITER = "<<&(*iter)<<std::endl;
}

The address of the iterator being returned is 16 Bytes graeter than
the address of the allocated memory. This is true in multiple
compilers, and is causing me to overwrite the end of my allocated
memory. It doesn't seem to matter what type of object Foo is.

has anyone seen this before or have any ideas?
Thanks,
Joe
 
F

Fei Liu

joe said:
I have written a custom std allocator which follows the example in
Stroustrup's book.

I'm seeing a behavior I don't understand.

My allocate method within the allocator looks like the following:
(FooAllocator<T>)

pointer allocate(size_type cnt, typename
std::allocator<void>::const_pointer hint = 0)
{
pointer p = reinterpret_cast<pointer> (new char[sizeof(T)*cnt]);

This is probably the cause of your problem. reinterpret_cast is not a
safe cast and it does not guarantee proper object alignment.

F
 
C

Charles Bailey

joe said:
pointer allocate(size_type cnt, typename
std::allocator<void>::const_pointer hint = 0)
{
pointer p = reinterpret_cast<pointer> (new char[sizeof(T)*cnt]);
std::cout<<"MEMORY ADDRESS: "<<p<<std::endl; //FIRST PRINT-OUT!
return p;
}

Just for fun change the log message to this:
std::cout <<"MEMORY ADDRESS: " << p << ", sizeof T is"
<< sizeof(T) << std::endl;
Then I have a regular container in my main:
int main()
{
typedef std::multiset<Foo,less<Foo>,FooAllocator<Foo> > MYSET;

MYSET mine;

MYSET::iterator iter = mine.insert(Foo());
std::cout<<"ITER = "<<&(*iter)<<std::endl;
}

The address of the iterator being returned is 16 Bytes graeter than
the address of the allocated memory. This is true in multiple
compilers, and is causing me to overwrite the end of my allocated
memory. It doesn't seem to matter what type of object Foo is.

&(*iter) is not the address of the iterator, it's the address of the
object "pointed" to by the iterator. As you can see, the object has a
different address to one you returned from the allocate call. This may
be because the instance of the allocator template that is being used is
probably not the one you think is being used.

Presumably you had to define a rebind struct, can you see what has happened?

If not, add some logging to your constructors, especially the templated one.
template<class U> FooAllocator(const FooAllocator<U>&)

Charles.
 
J

James Kanze

I have written a custom std allocator which follows the example in
Stroustrup's book.
I'm seeing a behavior I don't understand.
My allocate method within the allocator looks like the following:
(FooAllocator<T>)
pointer allocate(size_type cnt, typename
std::allocator<void>::const_pointer hint = 0)
{
pointer p = reinterpret_cast<pointer> (new char[sizeof(T)*cnt]);
std::cout<<"MEMORY ADDRESS: "<<p<<std::endl; //FIRST PRINT-OUT!
return p;
}
Then I have a regular container in my main:
int main()
{
typedef std::multiset<Foo,less<Foo>,FooAllocator<Foo> > MYSET;
MYSET mine;
MYSET::iterator iter = mine.insert(Foo());
std::cout<<"ITER = "<<&(*iter)<<std::endl;
}
The address of the iterator being returned is 16 Bytes graeter than
the address of the allocated memory. This is true in multiple
compilers, and is causing me to overwrite the end of my allocated
memory. It doesn't seem to matter what type of object Foo is.

Presumably (I don't see how one could implement it differently),
what is being allocated in the multiset is not a T, but some
sort of node structure containing a T, typically with a couple
of pointers before the T. And the actual type of the allocator
being used to do the allocation should not be T, but this node
type.

Having said this, I don't quite see how this could be causing
you to overwrite anything. The allocation expression should be
something like (typedef's expanded, etc.):

__Alloc::rebind<__Node>::eek:ther( myAlloc ).allocate( n )

If you're rebind declaration is correct, and the code for
allocate is really what you show, then you should have no
trouble in this respect; if you're not sure, add output of
typeid(T).name and sizeof(T) to your allocator, to see what is
going on.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top