Boost logo

Boost :

From: David Bergman (davidb_at_[hidden])
Date: 2004-02-11 18:33:21


Trey wrote:

> All,
>
> I'm loving the shared_ptr class,
> however we have one issue that doesn't seem to be addressed
> by any of boost's smart pointers, and I'm looking for a
> work-around/alternative.
> Any help?
>
> The issue is that the smart pointers assume the pointer type
> to be 'T*', which is fine on a 32-bit system, but means that
> we get a near doubling of run-time size on our application
> when we move to a 64-bit application.
>
> As a result, we're using the standard technique to have a
> custom heap, and use our own 'pointers' into that heap that
> are smaller (typically 32-bits).
>
> But of course our ClassOnHeapPtr type does not match a
> 'ClassOnHeap *', so a boost::shared_ptr<ClassOnHeap> won't work.
>
>
> Are there any other libraries you boosters would recommend?

I wrote a naive implementation now, based on a "heap" where I encode the
pointer to a pointer to the heap in compile-time.

It gives me smart pointers only occupying enough bits to cover the heap, in
my case 2 bytes.

The code is appended below.

One should, of course, use a generic smart pointer (e.g. Alexandrescu's
SmartPtr) and form a policy that does the offsetting trick, as David
Abrahams suggested. But till then, borrow some ideas from my crappy
implementation below...

PS
You can copy and paste the code fragment, as is. Please do and compile and
run.
DS

----------------------------------------------------------------------------
------------------------------------------

#include <memory>
#include <iostream>

namespace tj {

// First a Concept description of PointerBase, which is often
// a type-based implementation of a heap.
// Yes, assuming a default constructor for PointerBase types is
// not very nice...

template<typename PointerBase>
struct PointerBaseConcept {
  typedef typename PointerBase::diff_type diff_type;
  static void check() {
    // A pointer base should have '+' and '-' to convert from and to
    // offsets
    char* ptr = PointerBase() + static_cast<diff_type>(0);
    diff_type offset = ptr - PointerBase();
  }
};

// A simple Adapter type to char pointers, being a model
// of PointerBase. It needs a (compile-time deducible) pointer
// to the pointer to the beginning of the "heap." An extern
// variable holding a pointer will do.

template<char** baseHandle, typename OffsetType = size_t>
struct simple_pointer_base {
  typedef OffsetType diff_type;
  template<char** anyBase, typename AnyOffsetType>
  friend char* operator+(simple_pointer_base, diff_type diff);
  template<char** anyBase, typename AnyOffsetType>
  friend diff_type operator-(char*, simple_pointer_base);
};

template<char** baseHandle, typename OffsetType>
inline typename simple_pointer_base<baseHandle, OffsetType>::diff_type
  operator-(char* base, simple_pointer_base<baseHandle, OffsetType>)
{
  // Force the diff to be of the right type...
  return static_cast<typename simple_pointer_base<baseHandle,
OffsetType>::diff_type>(base - *baseHandle);
}

template<char** baseHandle, typename OffsetType>
inline char* operator+(simple_pointer_base<baseHandle, OffsetType>,
                       typename simple_pointer_base<baseHandle,
OffsetType>::diff_type diff)
{
  return *baseHandle + diff;
}

// The offset_ptr smart ptr uses a PointerBase type

template<typename T, typename PointerBase>
class offset_ptr {
public:
  typedef T* pointer;
  typedef T value_type;

  offset_ptr(pointer obj)
     : _offset(static_cast<char*>(static_cast<void*>(obj)) - PointerBase())
  {
    // empty
  }

  operator pointer() const
  {
    return static_cast<pointer>(static_cast<void*>(PointerBase() +
_offset));
  }

  pointer operator->() const
  {
    return static_cast<pointer>(*this);
  }

  value_type& operator*() const
  {
    return *static_cast<pointer>(*this);
  }
  typename PointerBaseConcept<PointerBase>::diff_type _offset;
};

} // end of namespace tj

using namespace std;
using namespace tj;

// Test the offset pointers

char* heap;

typedef simple_pointer_base<&heap, short> MyPointerBase;

int main(int argc, char* argv[])
{
  heap = new char[1000];
  PointerBaseConcept<MyPointerBase>::check();

  // We create a few primitive objects, manually placing them
  // in the "heap"

  char* nextPtr = heap;
  const int I1 = 35, I2 = 42;
  const double D1 = 66.7, D2 = 77.4;
  int *ip1 = new (nextPtr) int(I1);
  int *ip2 = new (nextPtr += sizeof(*ip1)) int(I2);
  double *dp1 = new (nextPtr += sizeof(*ip2)) double(D1);
  double *dp2 = new (nextPtr += sizeof(*dp1)) double(D2);

  // Output the sizes and referenced values of the pointers

  cout << "size(ip1)=" << sizeof(ip1) << ", *ip1=" << *ip1 << '\n';
  cout << "size(ip2)=" << sizeof(ip2) << ", *ip2=" << *ip2 << '\n';
  cout << "size(dp1)=" << sizeof(dp1) << ", *dp1=" << *dp1 << '\n';
  cout << "size(dp2)=" << sizeof(dp2) << ", *dp2=" << *dp2 << '\n';

  // Create the offset pointers

  typedef offset_ptr<int, MyPointerBase> MyIntOffsetPtr;
  MyIntOffsetPtr sip1(ip1);
  MyIntOffsetPtr sip2(ip2);
  typedef offset_ptr<double, MyPointerBase> MyDoubleOffsetPtr;
  MyDoubleOffsetPtr sdp1(dp1);
  MyDoubleOffsetPtr sdp2(dp2);

  // Output the sizes and referenced values of the pointers

  cout << "size(sip1)=" << sizeof(sip1) << ", *sip1=" << *sip1 << '\n';
  cout << "size(sip2)=" << sizeof(sip2) << ", *sip2=" << *sip2 << '\n';
  cout << "size(sdp1)=" << sizeof(sdp1) << ", *sdp1=" << *sdp1 << '\n';
  cout << "size(sdp2)=" << sizeof(sdp2) << ", *sdp2=" << *sdp2 << '\n';
}


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