bug-gplusplus
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

construct and destroy never called in STL allocators


From: Gokhan Kisacikoglu
Subject: construct and destroy never called in STL allocators
Date: Fri, 28 May 2004 12:42:30 -0700
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030703

Hi,

I am using gcc version 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2), but I saw the same problems with the newer versions of gcc as well in the stl containers.

I was trying to catch the construction and destruction of the actual instances in my stl allocator for a given container. The allocate and deallocate routines are always called, but all of the STL containers are calling the global construct and destroy methods instead of the ones defined in my allocator.

If this is not a bug, then I guess these two functions should be removed from the standard conforming allocator interfaces (in stl_alloc.h), because they are never used and very misleading for the users. I did expect initially that they would be called instead of the global ones.

I attached a simple code for the std::map case, that I fixed by specializing for the _Rb_tree_alloc_base template class for the allocators with an instance. I had to make the construct and destroy functions also templated, but I guess it could be worked out without those, the intend here was just to demonstrate that the current implementation does not call the construct and destroy for the user defined allocators.

Thanks,
Gokhan

#include <map>
#include <typeinfo>
#include <iostream>

using namespace std;

template <typename _T>
class TypeAllocator
{
public:
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef _T*       pointer;
    typedef const _T* const_pointer;
    typedef _T&       reference;
    typedef const _T& const_reference;
    typedef _T        value_type;
    
    template <typename _T1> struct rebind 
    {
        typedef TypeAllocator<_T1> other;
    };
    
    // ctor/dtors
    //
    TypeAllocator() {}
    TypeAllocator(const TypeAllocator &_other) {}
    template <typename _T1> TypeAllocator(const TypeAllocator <_T1> &_other) {}
    
    TypeAllocator &operator = (const TypeAllocator&_other) { return *this; }
    ~TypeAllocator() {}
    
    pointer address(reference _x) const { return &_x; }
    const_pointer address(const_reference _x) const { return &_x; }
    
    _T* allocate(size_type _n, const void* = 0)
    {
        return ((_n != 0) ? 
            static_cast <_T*> (base_alloc::allocate(_n * sizeof(_T))) : NULL);
    }
    
    void deallocate(pointer _p, size_type _n)
    {
        base_alloc::deallocate(_p, _n * sizeof(_T));
    }
    
    size_type max_size() const { return size_t(-1) / sizeof(_T); }
    
    template <typename _T1> void construct(_T1* _p, const _T1 &_val) 
    { 
        cerr << "ctruct: " << typeid(*this).name() << endl;
        new(_p) _T1(_val); 
    } 
    
    template <typename _T1> void destroy(_T1 *_p) 
    { 
        cerr << "dtruct: " << typeid(*this).name() << endl;
        _p->~_T1();
    }
    
private:
    typedef std::alloc base_alloc;          // The underlying allocator.
};

template<>
class TypeAllocator<void> {
  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 TypeAllocator<_Tp1> other;
  };
};

template <class _Tp, class _Alloc>
class _Rb_tree_alloc_base <_Tp, _Alloc, false> {
public:
  typedef typename _Alloc_traits<_Tp, _Alloc>::allocator_type allocator_type;
  allocator_type get_allocator() const { return _M_node_allocator; }

  _Rb_tree_alloc_base(const allocator_type& __a)
    : _M_node_allocator(__a), _M_header(0) {}

protected:
  typename _Alloc_traits<_Rb_tree_node<_Tp>, _Alloc>::allocator_type
           _M_node_allocator;
  _Rb_tree_node<_Tp>* _M_header;

  _Rb_tree_node<_Tp>* _M_get_node() 
    { return _M_node_allocator.allocate(1); }
  void _M_put_node(_Rb_tree_node<_Tp>* __p) 
    { _M_node_allocator.deallocate(__p, 1); }
    
    void construct(_Tp *__p, const _Tp &_value)
    {
        _M_node_allocator.construct(__p, _value);
    }

    void destroy(_Tp *__p)
    {
        _M_node_allocator.destroy(__p);
    }
};

typedef TypeAllocator <float> float_allocator;
typedef std::map <int, float, std::less <int>, float_allocator> IntMap;
typedef IntMap::key_compare map_key_compare;
typedef IntMap::value_type map_value_type;

int main(void)
{
    IntMap mm;
    mm = IntMap(map_key_compare(), float_allocator());
    mm.insert(make_pair(10, 100.0f));
    cerr << mm.find(10)->second << endl;
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]