
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'; }