• Advertisement
Sign in to follow this  

std::allocators

This topic is 4794 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Every std container allows to specify the allocator. In order to simplify the code I rewrote the allocator template class declaring some functions as virtual. This code works with my implementation of the STL but...does it work in general or not? In other words : is there a 'standard' allocator ? Have you seen different versions ?
template<class T>
class Allocator
{
public:

  typedef _SIZT	     size_type;
  typedef _PDFT	     difference_type;
  typedef T*	     pointer;
  typedef const T*   const_pointer;
  typedef T&	     reference;
  typedef const T&   const_reference;
  typedef T	     value_type;

  pointer address(reference x) const{
	return (&x); 
  }

  const_pointer address(const_reference x) const{
	return (&x); 
  }
	
  _SIZT max_size() const{
	_SIZT _N = (_SIZT)(-1) / sizeof(T);
	return (0 < _N ? _N : 1); 
  }
  
  
 // virtual functions
 
  // reserve memory for n objects (T)
  virtual pointer allocate(size_type n, const void *){
    return((pointer)new char[n*sizeof(T)]);
  }
	
  // reserve memory for n chars
  virtual char* _Charalloc(size_type n){
    return (new char[n]);
  }

  // deallocate an array (allocated with one of the previous func)
  virtual void deallocate(LPVOID p, size_type){
	delete[](p); 
  }
	
  // construct object *p (p is already a valid ptr)
  virtual void construct(pointer p, const T& v){
	new((LPVOID)p) T(v);
  }
	
  // destroy object *p
  virtual void destroy(pointer p){
	p->~T(); 
  }
      	 
};

Thanks!

Share this post


Link to post
Share on other sites
Advertisement
It looks okay, but the following need to be defined:
_SIZT (use size_t)
_PDFT (use ptrdiff_t)
placement new (#include <new>)

Also, what is your max_size supposed to do? I don't think size_t is guaranteed to be unsigned, so instead of -1 you should use std::numeric_limits<size_t>::max() instead. Come to think of it, I'm not sure numeric_limits is specialized for size_t...

Share this post


Link to post
Share on other sites
Aside from the above suggestions, I don't see why what you have wouldn't work. I don't know if I agree with using virtual functions in situations void of polymorphism to save yourself some extra typing, but if it suits you then go ahead [smile]

Share this post


Link to post
Share on other sites
The code I posted is the same of the STL I have...the only difference are those virtual declarations.

max_size() simply divide the biggest _SIZT number (that is -1 = ~0 = 1111..1) by T size...it returns how many objects you can have such that you can use a _SIZET to count the memory usage.

I suppose that _SIZET is an unsigned because it must describe a "SIZE" (never negative!)

Share this post


Link to post
Share on other sites
Your allocator is missing a very important part its missing the rebind type, STL container's type allocator parameter is not a template template type parameter, they will most definitely use the rebind class template to create allocator of not they actual type but nodes that contain them. Its easy to define just add:


template< typename T >
struct my_alloc {

template< typename Tp1 >
struct rebind {
typedef my_alloc<Tp1> other;
};

//.....
};


next when you call new normally its going to allocate & initialize the memory by invoking the constructor of the type in question (this includes primitive built-in types), to just allocate raw memory call new explicitly e.g.


::operator new(sizeof(T) * number_of_objs);


What is the purpose of making the methods virtual for? there is no way your going to be able to get STL containers to use your allocators polymorphiclly at run-time, not portably thats for sure, besides the allocator concept is polymorphic but its static polymorphism so its resolved at compile-time.

Quote:
Original post by blizzard999
In other words : is there a 'standard' allocator ?


yes its in the header memory and its called std::allocator.

Quote:
Original post by blizzard999
Have you seen different versions ?


Yes in gcc they have 7 different types of allocators for different memory management schemes, including the c++ standard allocator type, the others are available to use on GCC but this makes your program not very portable to other compilers.

Also boost library has a package of portable allocators (2 of them) which are a pooling schemes.

Share this post


Link to post
Share on other sites
Standard allocators have, traditionally, not been very portable, as the STL implementation has traditionally been depending on non-specified parts of their allocators. The only way to make sure your allocator works everywhere, is to test it everywhere.

That being said, I don't understand why you would need virtual functions. It's a template argument, so the type is resolved at compile time. The template way of resolving functions by name is all you need for this (and it's faster).

Share this post


Link to post
Share on other sites
I've done a simple cut and past from my STL implementation VC6...so I know it is the 'standard' allocator but for this specific version!
For example the help does not report the existence of the fuctions _Charallocc() but in the implementation it exists and it is used to allocate memory for list nodes.
I know that there are a lot of different allocators but they should have the same interface...and my problem is: what is this 'common' interface?
Yes, using virtual functions with templates is not so common, but it is not wrong!

Probably I should use different STL version..what about SGI one ?

Share this post


Link to post
Share on other sites
Quote:
Original post by hplus0603
Standard allocators have, traditionally, not been very portable, as the STL implementation has traditionally been depending on non-specified parts of their allocators. The only way to make sure your allocator works everywhere, is to test it everywhere.

That being said, I don't understand why you would need virtual functions. It's a template argument, so the type is resolved at compile time. The template way of resolving functions by name is all you need for this (and it's faster).


So the solution should be

- find the file where the allocator is defined ( something like xmemory )
- cut and paste the code actually used
- modify it

Right?

Share this post


Link to post
Share on other sites
Quote:
Original post by blizzard999
For example the help does not report the existence of the fuctions _Charallocc() but in the implementation it exists and it is used to allocate memory for list nodes.


Because that isn't part of standard allocator interface, its probably just internal helper method or hack around, VC++ 6.0 is broke when it comes to templates & standard compilancey in general.

Quote:
Original post by blizzard999
I know that there are a lot of different allocators but they should have the same interface...and my problem is: what is this 'common' interface?


You can use this as future reference:


template<typename _Tp>
struct my_allocator {

typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef const _Tp* const_pointer;
typedef _Tp& reference;
typedef const _Tp& const_reference;
typedef _Tp value_type;

template<typename _Tp1>
struct rebind { typedef my_allocator<_Tp1> other; };

my_allocator() throw();

my_allocator(const my_allocator&) throw();

template<typename _Tp1>
my_allocator(const my_allocator<_Tp1>&) throw();

~my_allocator() throw();

pointer address(reference) const;

const_pointer address(const_reference) const;

pointer allocate(size_type, const void* = 0);

void deallocate(pointer, size_type);

size_type max_size() const throw();

void construct(pointer, const _Tp&);

void destroy(pointer);
};

template<typename _Tp>
bool operator==(const my_allocator<_Tp>&, const my_allocator<_Tp>&);

template<typename _Tp>
bool operator!=(const my_allocator<_Tp>&, const my_allocator<_Tp>&);



if some of them that don't make sense to implement for your allocator like for example the copy constructor because your allocator has nothing to copy then just make the definition empty.

Quote:
Original post by blizzard999
Yes, using virtual functions with templates is not so common, but it is not wrong!


There isn't anything wrong we are just wondering why you want to do this.

Quote:
Original post by blizzard999
Probably I should use different STL version..what about SGI one ?


if your seriously going to continue to use VC++ 6.0 then i'd suggest getting STLport.

[Edited by - snk_kid on January 6, 2005 11:33:14 AM]

Share this post


Link to post
Share on other sites
I downloaded the STlport and this is its allocator definition


template <class _Tp>
class allocator {
public:

typedef _Tp value_type;
typedef value_type * pointer;
typedef const _Tp* const_pointer;
typedef _Tp& reference;
typedef const _Tp& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
# if defined (_STLP_MEMBER_TEMPLATE_CLASSES)
template <class _Tp1> struct rebind {
typedef allocator<_Tp1> other;
};
# endif
allocator() _STLP_NOTHROW {}
# if defined (_STLP_MEMBER_TEMPLATES)
template <class _Tp1> allocator(const allocator<_Tp1>&) _STLP_NOTHROW {}
# endif
allocator(const allocator<_Tp>&) _STLP_NOTHROW {}
~allocator() _STLP_NOTHROW {}
pointer address(reference __x) const { return &__x; }
const_pointer address(const_reference __x) const { return &__x; }
// __n is permitted to be 0. The C++ standard says nothing about what the return value is when __n == 0.
_Tp* allocate(size_type __n, const void* = 0) {
return __n != 0 ? __REINTERPRET_CAST(value_type*,__sgi_alloc::allocate(__n * sizeof(value_type))) : 0;
}
// __p is permitted to be a null pointer, only if n==0.
void deallocate(pointer __p, size_type __n) {
_STLP_ASSERT( (__p == 0) == (__n == 0) )
if (__p != 0) __sgi_alloc::deallocate((void*)__p, __n * sizeof(value_type));
}
// backwards compatibility
void deallocate(pointer __p) const { if (__p != 0) __sgi_alloc::deallocate((void*)__p, sizeof(value_type)); }
size_type max_size() const _STLP_NOTHROW { return size_t(-1) / sizeof(value_type); }
void construct(pointer __p, const _Tp& __val) { _STLP_STD::_Construct(__p, __val); }
void destroy(pointer __p) { _STLP_STD::_Destroy(__p); }
# if defined(__MRC__)||(defined(__SC__) && !defined(__DMC__))
template <class _T2> bool operator==(const allocator<_T2>&) const _STLP_NOTHROW { return true; }
template <class _T2> bool operator!=(const allocator<_T2>&) const _STLP_NOTHROW { return false; }
# endif
};


Share this post


Link to post
Share on other sites
Quote:
Original post by blizzard999
I downloaded the STlport and this is its allocator definition


There is alot of stuff going on there to handle the case of STLport being used on compilers such as VC++ 6.0 (that is where the port part of STLport comes in) as i said before the compiler is borked & pre-dates the standard, STLport is good for older compilers but i wouldn't base your own code on it unless you want to get something to work that VC++ 6.0 can't handle ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by blizzard999
STLport is tested for MSVC 4,5,6
Nothing about VC7


VC7 has a perfectly fine implementation of the STL and is standard-compliant to boot. If you have VC7, dont' use STLport.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement