[Gc] Using C++ Standard Template Library with GC

Andrew Begel abegel@cs.berkeley.edu
Mon, 10 Nov 2003 17:36:11 -0800


We use new_gc_alloc.h with the STL containers fairly successfully. We 
don't define any extra flags from the default except we add 
ATOMIC_UNCOLLECTABLE.


Here's our header file which pulls in the gc as well as a sample STL 
container:

#if defined(__GNUC__) && __GNUC__ >= 3
# define __STL_BEGIN_NAMESPACE namespace std {
# define __STL_END_NAMESPACE }
# define __STL_USE_STD_ALLOCATORS
#if __GNUC_MINOR__ >= 1
#define simple_alloc __simple_alloc
#else
#define USE_NEW_GC_ALLOC 1
#endif
#elif !defined(__GNUC__) /* __GNUC__ */
# define __STL_BEGIN_NAMESPACE namespace std {
# define __STL_END_NAMESPACE }
#endif /* __GNUC__ */


#ifndef __GNUC__
// non-GNU compilers don't have simple_alloc template (e.g. MSVC, Sun 
cc)
template<class _Tp, class _Alloc>
class simple_alloc {

public:
     static _Tp* allocate(size_t __n)
       { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof 
(_Tp)); }
     static _Tp* allocate(void)
       { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); }
     static void deallocate(_Tp* __p, size_t __n)
       { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); }
     static void deallocate(_Tp* __p)
       { _Alloc::deallocate(__p, sizeof (_Tp)); }
};

template <class _Tp, class _Allocator>
struct _Alloc_traits
{
   static const bool _S_instanceless = false;
   typedef typename _Allocator::template rebind<_Tp>::other
           allocator_type;
};

template <class _Tp, class _Allocator>
const bool _Alloc_traits<_Tp, _Allocator>::_S_instanceless;

#endif

#include <gc/new_gc_alloc.h>  // here's the garbage collector include

// this is similar to what is in gc_allocator.h
template<class _Tp>
class gc_typed_allocator : public single_client_gc_alloc {
public:
     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 <class _Tp1> struct rebind {
		typedef gc_typed_allocator<_Tp1> other;
     };

     gc_typed_allocator() {}

     gc_typed_allocator(const single_client_gc_alloc&) {}

     gc_typed_allocator<_Tp>& operator=(const single_client_gc_alloc&) {
	return (*this);
     }

     size_t max_size() const {
	return (size_t)(-1) / sizeof (_Tp);
     }

     void construct(pointer ptr, const_reference val) {
	*ptr = _Tp(val);
     }

     void destroy(pointer ptr) {
	ptr->~_Tp();
     }
	
     pointer allocate(size_type n, const void * /*hint*/ = 0) {
	pointer ret = (pointer)single_client_gc_alloc::allocate(n * 
sizeof(_Tp));
	return ret;
     }
};

// specialization of typed_allocator for <void>, which is not allowed to
// have reference types
template<>
class gc_typed_allocator<void> : public single_client_gc_alloc {
public:
     typedef size_t     size_type;
     typedef ptrdiff_t  difference_type;
     typedef void*       pointer;
     typedef const void* const_pointer;
     typedef void        value_type;
     template<class _Tp1> struct rebind {
	typedef gc_typed_allocator<_Tp1> other;
     };
};

class gc_allocator : public single_client_gc_alloc {
public:
     typedef size_t     size_type;
     typedef ptrdiff_t  difference_type;
     template <class _Tp1> struct rebind {
	  typedef gc_typed_allocator<_Tp1> other;
     };
};

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

Here's our use of the above header, call it alloc.h



#include "alloc.h"
#include <vector>

// the following code pulls std::vector into the unnamed namespace but 
uses the garbage collector for the
// allocator. It only works on gcc >= 3.0.

#if !(defined(__GNUC__) && __GNUC__ < 3)
template <class _type, class _alloc>
class vector : public std::vector<_type, gc_typed_allocator<_type> > {
private:
     typedef std::vector<_type, gc_typed_allocator<_type> > base;
public:
     vector()
	: base() {}
     vector(size_t __n,
	   const _type& __value,
	   const _alloc& __a = _alloc())
	: base(__n, __value, __a) {}
     vector(size_t __n)
	: base(__n) {}
     template <class _InputIterator>
	vector(_InputIterator __first,
	       _InputIterator __last,
	       const _alloc& __a = _alloc())
	: base(__first, __last, __a) {}
};
#endif


Andrew Begel


On Nov 9, 2003, at 1:23 PM, teelf@nymph.kyndig.com wrote:

>
> I was also having problems with classes derived from gc being used in 
> STL
> containers.  I recompiled the collector with
> -DREDIRECT_MALLOC=GC_malloc_uncollectable and it has been working on my
> linux 2.4.9 system.
>
> Is this another way of solving the STL problem? Or is there going to be
> problems later on down the road when my application gets more 
> thoroughly
> tested?
>
> Also, I think there is a small typo in the comments at the top of the 
> page
> in gc_alloc.h and new_gc_alloc.h.  It recommends using
> GC_uncollectable_malloc which should be GC_malloc_uncollectable.
>
> In response to an email from David Jones on 30 Oct 2003:
>> The basic problem is that STL containers need to allocate memory, and 
>> by
>> default they do so in the "malloc heap", which is neither scanned nor
>> collectible.
>
>> You need to allocate from a collectible heap.
>
>
> _______________________________________________
> Gc mailing list
> Gc@linux.hpl.hp.com
> http://linux.hpl.hp.com/cgi-bin/mailman/listinfo/gc