Boost logo

Boost :

From: scleary_at_[hidden]
Date: 2001-05-22 08:47:17

> There is also a good reason for default ctor: to make an instance
> which is later assigned to.

This could be useful as optional behavior. Most containers, though,
wouldn't allow such an assignment after construction (Does it really make
sense? What if objects have already been allocated? ...).

> Can Felix GC use/be a standard allocator?

I think so.

> To _use_ Felix GC as an allocator, we have to solve
> the problem: where does the shape information come from?
> The allocator knows the T, so it could use a 'traits'
> style thingo to get the shape object. It is also possible
> to build a (global) map typeid(T) -> shape for T.
> This prevents more than one shape per type.

Or just have the shape info be static public data (yuck!) of your Felix
  template <typename T>
  class felix_allocator
      // sizeof(T) we already know
      static void (*finaliser)(collector_t *, void *);
      static int num_offsets;
      static size_t *offsets;

> Unfortunately, I cannot see a way for the Felix operator new
> to work. That function is type independent (it gets sizeof(T),
> and forgets the T). So "new" functions cannot call allocators
> to get hold of memory.
> This problem can be solved by using a templated function
> that calls the Felix allocator. Unfortunately, that technique
> prevents initialisation of the object!

Yes, the usage of allocators generally requires allocation and
initialization to be separated (unless you're just doing a simple copy
construction). Just remember that you *do* have the power of placement new:
  my_allocator<T> a;
  T * p = a.allocate();
  new (p) T(_all constructor args_);

Another option is to create a family of template functions (like I did in
object_pool, called "construct") that does this for you. However, this is:
  1) Messy (but maybe that new CPP library will help here),
  2) Restricting (you can only define a finite number of them)

> I'd be interested if anyone can see how to make the Felix GC
> either USE a standard allocator to allocate memory

To use a standard allocator, what's to prevent you from doing:
  // My allocator class, templated on Allocator parameter...
  template <typename T, typename Allocator = std::allocator<T> >
  class felix_allocator
      // The actual objects that we allocate
      struct raw_memory_t
        frame_t frame;
        T data;
      // The type of allocator used to allocate raw_memory_t objects
      typedef typename Allocator::template rebind<raw_memory_t>::other

      // In final code, you'll probably want to privately derive to
      // make use of empty base optimization.
      RawAllocator a;

      // User wants a T allocated
      void * allocate(std::size_t n)
        // Got a plan for handling allocations of arrays???
        assert(n == 1);
        // Allocate the necessary memory
        raw_memory_t * ret = a.allocate(1);
        // Initialize ret->frame
        // Return the user's pointer (just the data)
        return &ret->data;

Or maybe I'm just overlooking something -- I've only taken a brief look at
your GC so far...

Also, when I did Pool, I started out trying to make it Standard-compatible
allocators &tc., but it ended up being way too messy! In the final design,
I wrote the basic Pool classes using my own sensible semantics, and wrote a
Standard Allocator _interface_ to these. You might want to consider a
similar approach... One other thing -- I allowed the users to define how
Pools allocate memory, but *not* through the Standard Allocator interface --
I defined my own more limited UserAllocator interface instead (doesn't allow
instance-based allocators). It's just so much simpler that way!

I guess what I'm saying is: don't mess your code up trying to force it into
a Standard -- just write it naturally, and then provide a Standard interface
if possible.


Boost list run by bdawes at, gregod at, cpdaniel at, john at