Nonstandard allocator::pointer in containers

Martin Sebor sebor@roguewave.com
Mon May 23 18:35:00 GMT 2005


Phil Endecott wrote:
...
> In my case there is just a single shared region, so the allocator state 
> is just the start address of the region and can be kept in a per-process 
> global.  For a more general solution with multiple shared regions, 
> allocators would need state.  (Have I understood you correctly?)

Yes. In your case it sounds like you may not need to maintain any
state in the allocator.

> 
>>> [is it] just a case of doing a search-and-replace of T* by 
>>> _Alloc::pointer. 
> 
> 
>> IIRC, it was a lot more work than just that. With user-defined
>> pointers you can't make many of the assumptions and optimizations
>> that you can otherwise. For example, you can't assume that such
>> pointer types are convertible to true pointers (such as void*),
>> you might need to be prepared to deal with exceptions where they
>> normally cannot occur, you can't use memcpy to copy objects of
>> user-defined pointers, etc.
> 
> 
> Again in my case I don't think I have much to worry about; I don't throw 
> any exceptions, my offsets are implicitly convertable to pointers, and 
> memcpy() is fine.  Though I am probably missing something!

No, I don't think you are :) Again, in your case you might be able
to get away with the assumptions that a library implementor cannot
make in general.

> I suppose 
> that what is really needed is some list of required characteristics of a 
> pointer type: Martin, is this written down anywhere for the Roguewave 
> implementation?

We have blurb somewhere about stateful allocators but, AFAIK,
the support for user-defined pointer types is not documented.

> Here is a prototype of my offset class:

I think you will need to sprinkle a few consts here and there to get
things to compile. You might also need to implement the usual operators
(increment, decrement, etc.) I don't have the time right now to play
with it to see what else it needs but below is a definition of
a pointer class from one of our tests (it's probably fatter than
it needs to be). It compiles with all containers except for list.

> 
>     template <typename T>
>     class offset {
>      private:
>       int o;
>       T* getptr(void) {
>     return o ? (reinterpret_cast<T*>(o + reinterpret_cast<int>(region)))
>       : NULL;
>       }
> 
>      public:
>       offset(): o(0) {}
>       offset(const offset<T>& ofs): o(ofs.o) {}
>       offset(T* p):
>     o ( p ? (reinterpret_cast<int>(p) - reinterpret_cast<int>(region))
>         : 0 ) {}
>       operator T* (void) { return getptr(); }
>       T& operator*(void) { return * getptr(); }
>       T* operator->(void) { return getptr(); }
>       operator bool (void) { return o; }
>     };
> 
> 
>>> (Or maybe I can just paste in the Roguewave one?)
> 
> 
> [This is obviously O.T. for the libstdc++ list, but Martin I'd be 
> interested to know whether you'd expect me to be able to get map<> and 
> vector<char> functionality just by shipping the headers, or whether 
> there is support code in the library that is needed too.]

Most of our headers depend on the library binary for a couple of
memory management functions (simple wrappers for new and delete)
and exception handling (construction and throwing) but eliminating
the dependency shouldn't be too hard.

Martin

template <class T>
class Pointer
{
public:
     typedef T                          value_type;
     typedef size_t                     size_type;
     typedef ptrdiff_t                  difference_type;
     typedef value_type*                pointer;
     typedef const value_type*          const_pointer;
     typedef value_type&                reference;
     typedef const value_type&          const_reference;
     typedef random_access_iterator_tag iterator_category;

     Pointer (): offset_ (0) { }

     Pointer (const Pointer &rhs)
         : offset_ (rhs.offset_) { }

     // The int argument is a dummy argument to distinguish this constructor
     // from Pointer (T*).
     Pointer (difference_type off, int) : offset_ (off) {}

     Pointer (const_pointer ptr)
         : offset_ (_RWSTD_REINTERPRET_CAST (difference_type, ptr)) { }

     operator const void* () const {
         return _RWSTD_REINTERPRET_CAST (const_pointer, offset_);
     }

     operator void* () const {
         return _RWSTD_REINTERPRET_CAST (pointer, offset_);
     }

     reference operator* () const {
         return *_RWSTD_REINTERPRET_CAST (pointer, offset_);
     }

     pointer operator-> () const {
         return _RWSTD_REINTERPRET_CAST (pointer, offset_);
     }

     difference_type offset () const {
         return offset_;
     }

     bool operator== (const Pointer &rhs) const {
         return offset_ == rhs.offset_;
     }

     bool operator!= (const Pointer &rhs) const {
         return !operator== (rhs);
     }

     bool operator< (const Pointer &rhs) const {
         return offset_ < rhs.offset_;
     }

     bool operator<= (const Pointer &rhs) const {
         return !(*this > rhs);
     }

     bool operator> (const Pointer &rhs) const {
         return rhs < *this;
     }

     bool operator>= (const Pointer &rhs) const {
         return !(*this < rhs);
     }

     Pointer& operator++ () {
         pointer ptr = _RWSTD_REINTERPRET_CAST (pointer, offset_);
         offset_ = _RWSTD_REINTERPRET_CAST (difference_type, ++ptr);
         return *this;
     }

     Pointer operator++ (int) {
         Pointer tmp = *this;
         return ++*this, tmp;
     }

     Pointer& operator-- () {
         pointer ptr = _RWSTD_REINTERPRET_CAST (pointer, offset_);
         offset_ = _RWSTD_REINTERPRET_CAST (difference_type, --ptr);
         return *this;
     }

     Pointer operator-- (int) {
         Pointer tmp = *this;
         return --*this, tmp;
     }

     Pointer& operator+= (difference_type i) {
         pointer ptr = _RWSTD_REINTERPRET_CAST (pointer, offset_);
         offset_ = _RWSTD_REINTERPRET_CAST (difference_type, ptr += i);
         return *this;
     }

     Pointer& operator-= (difference_type i) {
         return *this += -i;
     }

     Pointer operator+ (difference_type i) const {
         return Pointer (*this) += i;
     }

     Pointer operator- (difference_type i) const {
         return Pointer (*this) -= i;
     }

     ptrdiff_t operator- (const Pointer &rhs) const {
         pointer p1 = _RWSTD_REINTERPRET_CAST (pointer, offset_);
         pointer p2 = _RWSTD_REINTERPRET_CAST (pointer, rhs.offset_);
         return p1 - p2;
     }

private:
     difference_type offset_;
};



More information about the Libstdc++ mailing list