Boost logo

Boost :

From: Beman Dawes (beman_at_[hidden])
Date: 2000-01-12 17:07:40


At 11:24 AM 1/12/00 -0800, Greg Colvin wrote:

>From: Beman Dawes <beman_at_[hidden]>
>> In implementing a B-tree Container for boost, I have a smart
pointer
>> need which can't be met by boost::shared_ptr<>; an intrusive
>> reference count is required. (Of the three reasons, the last one
is
>> the killer.)
>>
>> * Since the smart point goes in an iterator, it would be better
to
>> avoid the size and separate allocation penalty of shared_ptr.
>>
>> * Memory allocation should use the container's Allocator.
>>
>> * The smart pointer needs to support construction from a raw
pointer
>> when other smart pointers to the same object are known to exist,
but
>> are not available. This means there needs to be a constructor
which
>> increments the reference count rather than just setting it to 1.
>> (This need derives from a really nice cache design which holds raw
>> pointers rather than smart pointers. If smart pointers where
held,
>> the cached pages would never get released.)
>
>So you are using the raw pointers as weak pointers in this design?

Well, not really, if I understand your definition of weak_ptr. There
is no signal when the object is collected.

Here is much cut down code, called shared_in_ptr for lack of a better
name. Note the smart pointer's second constructor increments the use
count rather than setting it to 1.

Following the shared_in_ptr implementation is a usage example. Hope
this makes it clearer.

--Beman

--- shared_in_ptr header ---

// shared_in_base

// This base class meets the requirements for shared_in_ptr T, and
keeps the count
// private to prevent abuse. Note that shared_in_ptr does not
require inheriting
// from shared_in_base<> as long as shared_in_ptr<> requirements are
met
// (presumably by simply providing a member named btree_in_count).

// Requirements on RefCounter: must meet shared_in_ptr requirements.
For example,
// int or long.

template<typename RefCounter>
class shared_in_base
{
    template<typename U> friend class shared_in_ptr;
    RefCounter btree_in_count;
};

// shared_in_ptr

// Requirements: For px of type T*, the following are well-formed
and do not
// throw exceptions.
//
// Expression Type Effects
// ========== ======== =======
// px->btree_in_count=1 --- sets px->btree_in_count to
value of 1.
// ++px->btree_in_count --- increments px->btree_in_count
by one.
// --px->btree_in_count integral decrements px->btree_in_count
by one,
// type returns px->btree_in_count.
// px->btree_in_count integral returns px->btree_in_count.
// type

template<typename T> class shared_in_ptr {
  public:
   typedef T element_type;

   explicit shared_in_ptr(T* p =0) : px(p) // usual ctor
      { if (px) px->btree_in_count = 1; }

   shared_in_ptr(T* p, bool) : px(p) // special ctor
      { assert(px); ++px->btree_in_count; }

   ~shared_in_ptr() { dispose(); }

   T& operator*() const throw() { return *px; }
   T* operator->() const throw() { return px; }
   T* get() const throw() { return px; }

   private:

   T* px; // contained pointer

   void dispose()
      { if (px && --px->btree_in_count == 0) { delete px; } }
}; // shared_in_ptr

---- shared_in_ptr usage example -----

// definitions

typedef int id_t;

struct cached_object;

map<id_t, cached_object*> cache;

struct cached_object : shared_in_base<int> {
  id_t _id
  cached_object( id_t id) : _id(id)
     { cache.insert( make_pair( _id, this ) ); }
  ~cache_object() { cache.erase( _id ); }
  // ... useful members here
  };

typedef shared_in_ptr<cached_object> obj_ptr;

// function to get cached_objects given id

obj_ptr get_cached_object( id_t id )
{
   cache::iterator itr = cache.find(id),
   if ( itr == cache.end() )
      // not found
      return obj_ptr(new cached_object(id));
   else
      // found
      return obj_ptr( itr.second, true ); // note 2nd arg
}


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