Boost logo

Boost :

From: E. Gladyshev (egladysh_at_[hidden])
Date: 2003-08-29 00:48:06


--- Gregory Colvin <gregory.colvin_at_[hidden]> wrote:
[...]
> > In this solution, there are some issues with who
> > controls the instances of the allocator that allocates
> > Data and instances that delete the Data.
>
> Which issues concern you?

The potential problem is this. Let's assume that
I forgot (or didn't know) that shared_ptr creates
a copy of Deleter.
I can technically create a local allocator class
that will keep the heap control block
as a data memeber.

*pseudo-code*

template< typename T >
sturct my_allocator
{
   my_heap_control _heap;

   T* create()
   {
      return _heap.create();
   }
   void operator()( T* d )
   {
      _heap.destroy(d);
   }
};

Now if I do something like the following code (that looks perfecly fine).

f()
{
  my_allocator<int> a;

  {
     shared_ptr<int> s( a.create(), a );
     ...
     int* n = a.create();
     a(n);
  }
}

I got a problem, because by the time when 's' deletes my data
the heap state is changed while 's' still has an old copy
of the heap state.

* If we state that boost allocators must be implemented
like statless policies not like real data types,
this problem is not a big deal.

>
> > But I guess it is not big deal as soon as people understand it.
> > If are to use template template parameters,
>
> Yes, the template template parameter is a pain. Probably better to
> take an arbitrary allocator object and rebind it:
>
> template<class Y, class D, class A>
> shared_ptr(T* p, D d, const A& a)
> : px(p), pn(p, d, A::rebind<<detail::sp_counted_base_impl<Data*,D>
> >(a))
> {
> detail::sp_enable_shared_from_this(p, p, pn);
> }
>
> > it would be nice to be able to define one allocator
> > type for both counter and data.
> >
> > template<typename Data, template<class>
> > class Allocator>
> > shared_ptr(
> > Data*,
> > Allocator<Data>,
> > const Allocator<boost::detail::sp_counted_base_impl<Data*,
> > Deleter> >& );
>
> This constructor would conflict with the constructors that take a
> deleter, which must be a function pointer or function object, and
> which might not use an allocator.

Right, a new constructor is not needed.

> But for the purpose of creating shared objects using an allocator
> you could instead use a factory function something like:
>
> template<class Allocator,typename Data>
> shared_ptr<T>
> allocate_shared_data(const Data& data, Allocator allocator)
> {
> struct deleter {
> Allocator a;
> deleter(const Allocator& a) : a(a) {}
> void operator()(Data* p) {
> a.deallocate(p,1);
> a.destroy(p);
> }
> };
> Data* p = allocator.allocate(1);
> allocator.construct(p,data);
> return shared_ptr<Data>(p,deleter<Data>(allocator),allocator);
> }

I like it.

Or you can add operator()(Data*) to your allocator
and use it directly in shared_ptr and STL.

template< typename T >
struct my_allocator : std::alocator<T>
{
   void operator()(T* d)
   {
     try
     {
       d->~T();
     }
     catch(...)
     {
       deallocate(d, 1);
       throw std::runtime_error("");
     }
     deallocate(d, 1);
     return;
   }
};

shared_ptr<Data> s( p, my_allocator<Data>(), my_allocator() );

I am not sure how to specify the counter allocator in this case
What is legal syntax for template template parameters in functions?
Do you have to put the whole thing in.

shared_ptr<Data> s( p, my_allocator<Data>(), my_allocator<p,my_allocator<Data> >() );

or there is another way?

Eugene

__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free, easy-to-use web site design software
http://sitebuilder.yahoo.com


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk