STL allocators, global new/delete using the heap and shared memory

  • Follow


I have a large C++ program that needs to allocate memory for
its objects using shared memory (don't ask why).  Meyers III
item 10 says "most of the standard containers never ask
their associated allocator for memory".  So this suggests to
me that I should replace global new/delete with my allocator
that uses shared memory.

However, the program is worked on by many people and some of
these developers want to be able to allocate memory from the
heap rather than from shared memory as and when it suits
them.  They prefer that global new gets memory from the heap
so that they can get memory from the heap this way rather
than using malloc.  So this suggests that I cannot replace
global new/delete with versions that use shared memory.

It is a mystery to me how these developers cope with the
fact of Meyers III item 10. They seem to think the problem
is solved by declaring the STL variable with a custom STL
allocator.

What to do? Has anyone else used a non-default allocator to
allocate most of the object types for a program?  Including
those types defined in the STL? (where one cannot provide a
new operator in the class).

My gut feeling is that I must replace global new/delete,
that custom STL allocators are not required and anyone that
wants to use the heap has to use malloc.  Any thoughts?

Regards,

Andrew Marlow

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply apm35 4/23/2004 10:39:24 AM

In article <d1a33011.0404220518.3b5d2bcf@posting.google.com>,
 apm35@student.open.ac.uk (apm) wrote:

> I have a large C++ program that needs to allocate memory for
> its objects using shared memory (don't ask why).  Meyers III
> item 10 says "most of the standard containers never ask
> their associated allocator for memory".  

Read the item more carefully.  The quoted statement doesn't mean that 
they simply ignore the allocator; they do however often need to rebind 
it to another type before asking for memory.

> However, the program is worked on by many people and some of
> these developers want to be able to allocate memory from the
> heap rather than from shared memory as and when it suits
> them. [...] 
> 
> It is a mystery to me how these developers cope with the
> fact of Meyers III item 10. They seem to think the problem
> is solved by declaring the STL variable with a custom STL
> allocator.

It is, as long as the allocator provides a correctly implemented rebind.  
In effect, it has to be a template able to cope with whatever 
implementation type the container actually wants to allocate memory for, 
not just the type nominally being contained.  If all it is doing is 
allocating from shared memory instead of the heap, this shouldn't be a 
problem.

Best wishes,
Matthew Collett

-- 
Those who assert that the mathematical sciences have nothing to say
about the good or the beautiful are mistaken.          -- Aristotle


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Matthew 4/23/2004 11:36:46 PM


apm35@student.open.ac.uk (apm) writes:

> I have a large C++ program that needs to allocate memory for
> its objects using shared memory (don't ask why).  Meyers III
> item 10 says "most of the standard containers never ask
> their associated allocator for memory".

No. He says '... most of the standard containers never make a 
    single call to the allocators with which they are *instantiated*'

Emphasis mine, and I think the difference is essential. Re-read item
    10.

std::list<t, apm_alloc> is instantiated with apm_alloc. But it uses
    apm_alloc::rebind<internal_list_node_type>::other for allocating
    nodes. (typically). It is assumed that
    apm_alloc::rebind<...>::other will be implemented by the user, to
    do the 'right' thing.

> So this suggests to
> me that I should replace global new/delete with my allocator
> that uses shared memory.

I think you should typedef apm_alloc::rebind<...>::other to your own
    allocator.

Below is an example. It prints out 'I am being used!' when the
    allocator's alloc function is used. This works with g++ 3.4.0,
    g++ 3.3.3, and even g++ 2.95.3, which is very old and has an stl
    cloned from sgi some time in the late palaeolithic. I believe it
    is conforming, except for the '#include<ostream>' which I forgot.

#include<list>
#include<memory>
#include<iostream>

template<class unit> struct talky_allocator;

template<>
struct talky_allocator<void>
{
  typedef void* pointer;
  typedef void const* const_pointer;
  typedef void value_type;
  template<class other_unit>
    struct rebind
    {
      typedef talky_allocator<other_unit> other;
    };
};

template<class unit>
struct talky_allocator
{
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  typedef unit* pointer;
  typedef unit const* const_pointer;
  typedef unit& reference;
  typedef unit const& const_reference;
  typedef unit value_type;
  
  template<class other_unit>
    struct rebind
    {
    /****************************************************************
    This typedef is very important! if you typedef it to
        std::allocator<other_unit> your allocator will not be used.
    */
      typedef talky_allocator<other_unit> other;
    };

  /*
  talky_allocator(talky_allocator const&)throw();
  ~talky_allocator()throw();
  */
  talky_allocator()throw(){}
  template<class other_unit>
    talky_allocator(talky_allocator<other_unit> const&)throw(){}

  pointer address(reference x) const{return &x;}
  const_pointer address(const_reference x)const{return &x;}

  pointer allocate
    (size_type s, talky_allocator<void>::const_pointer = 0)
  {
    std::cout << "I am being used!" << std::endl;
    return static_cast<pointer>(::operator new(s));
  }

  void deallocate(pointer p, size_type s)
  {
    std::cout << "I am being used to deallocate!" << std::endl;
    return ::operator delete(p);
  }
  size_type max_size() const throw()
  {return INT_MAX;}

  void construct(pointer p, const unit& value)
  {new(p)unit;}
  void destroy(pointer p){p->~unit();}
  
};


int main()
  {
    std::list<int, talky_allocator<int> > l;
    for(int i= 0 ; i < 10 ; ++i)
    {
      l.push_back(i);
    }
  }


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply llewelly 4/24/2004 12:24:29 AM

apm wrote:
> I have a large C++ program that needs to allocate memory for
> its objects using shared memory (don't ask why).  Meyers III
> item 10 says "most of the standard containers never ask
> their associated allocator for memory".  So this suggests to
> me that I should replace global new/delete with my allocator
> that uses shared memory.
<snip>

I don't have this book to hand any more, but I do recall this item and
I believe you have misunderstood it.

Most of the containers need to allocate "nodes" containing an element
and some other information, e.g. forward and back pointers for a list
node.  Instead of using the given allocator type, which can only
allocate arrays of the element type, they use
allocator::rebind<node_type>::other.  So you must make sure to define
the rebind member template correctly in your shared memory allocator.

(With the library supplied with Visual C++ 5 or 6, you must instead
implement a member function: char * _Charalloc(size_type).)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Ben 4/24/2004 12:37:21 AM

apm35@student.open.ac.uk (apm) wrote in message news:<d1a33011.0404220518.3b5d2bcf@posting.google.com>...
> What to do? Has anyone else used a non-default allocator to
> allocate most of the object types for a program?  Including
> those types defined in the STL? (where one cannot provide a
> new operator in the class).

I know its considered bad form to respond to your own post
but I have had a response from Scott Meyers that sheds
alot of light on the issue. I mis-read ESTL item 10.
When it says "most of the std containers never make a
single call to the allocators with which they were
instantiated" I mis-read that as the allocator is not used.
Actually the allocator does get used but not the
particular instantiation you might expect (it gets
a different one via the rebind mechanism).

So I do have a way to declare an STL variable with
an allocator of my choice. SO my next question is,
will this work if I declare the variable without
specifying the allocator template parameter but
rather giving the allocator as a constructor argument?
I hope so.....

-Andrew M.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply apm35 4/24/2004 12:49:26 AM

4 Replies
474 Views

(page loaded in 0.482 seconds)


Reply: