Custom Allocator Question - Advanced.

Discussion in 'C++' started by joe, May 23, 2007.

  1. joe

    joe Guest

    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
     
    joe, May 23, 2007
    #1
    1. Advertising

  2. joe

    Fei Liu Guest

    joe wrote:
    > 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
    > 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
    >
     
    Fei Liu, May 23, 2007
    #2
    1. Advertising

  3. joe wrote:
    > 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.
     
    Charles Bailey, May 23, 2007
    #3
  4. joe

    James Kanze Guest

    On May 23, 9:46 pm, joe <> wrote:
    > 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.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 24, 2007
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Brian Genisio
    Replies:
    12
    Views:
    8,055
    tom_usenet
    Jan 15, 2004
  2. Alex Vinokur
    Replies:
    16
    Views:
    12,309
    Alex Vinokur
    Aug 16, 2004
  3. Romeo Colacitti

    Custom memory allocator - alignment

    Romeo Colacitti, Mar 4, 2005, in forum: C Programming
    Replies:
    4
    Views:
    755
    Chris Torek
    Mar 7, 2005
  4. joe
    Replies:
    0
    Views:
    335
  5. Michele Simionato
    Replies:
    1
    Views:
    604
    Lacrima
    Mar 27, 2010
Loading...

Share This Page