Search code examples
c++visual-studiovisual-studio-2008releaseallocator

Custom allocator for STL fails to compile in release mode only


I have written a custom allocate which i'm using with std::vector. The code compiles and works when in debug mode, but it fails to compile in release mode with a strange error.

Here is my allocator :

template< class T >
class AllocPowOf2
{
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;

private:

   size_type m_nMinNbBytes;

public:

   template< class U >
   struct rebind
   {
       typedef AllocPowOf2< U > other;
   };

   inline pointer address( reference value ) const
   {
       return & value;
   }

   inline const_pointer address( const_reference value ) const
   {
       return & value;
   }

   inline AllocPowOf2( size_type nMinNbBytes = 32 )
    : m_nMinNbBytes( nMinNbBytes ) { }

   inline AllocPowOf2( const AllocPowOf2 & oAlloc )
    : m_nMinNbBytes( oAlloc.m_nMinNbBytes ) { }

   template< class U >
   inline AllocPowOf2( const AllocPowOf2< U > & oAlloc )
    : m_nMinNbBytes( oAlloc.m_nMinNbBytes ) { }

   inline ~AllocPowOf2() { }

   inline bool operator != ( const AllocPowOf2< T > & oAlloc )
   {
      return m_nMinNbBytes != oAlloc.m_nMinNbBytes;
   }

   inline size_type max_size() const
   {
       return size_type( -1 ) / sizeof( value_type );
   }

   static size_type OptimizeNbBytes( size_type nNbBytes, size_type nMin )
   {
      if( nNbBytes < nMin )
      {
         nNbBytes = nMin;
      }
      else
      {
         size_type j = nNbBytes;

         j |= (j >>  1);
         j |= (j >>  2);
         j |= (j >>  4);
         j |= (j >>  8);

#if ENV_32BITS || ENV_64BITS
         j |= (j >> 16);
#endif
#if ENV_64BITS
         j |= (j >> 32);
#endif
         ++j; // Least power of two greater than nNbBytes and nMin

         if( j > nNbBytes )
         {
            nNbBytes = j;
         }
      }
      return nNbBytes;
   }

   pointer allocate( size_type nNum )
   {
      return new value_type[ OptimizeNbBytes( nNum * sizeof( value_type ), 32 ) ]; // ERROR HERE, line 97
   }

   void construct( pointer p, const value_type & value )
   {
      new ((void *) p) value_type( value );
   }

   void destroy( pointer p )
   {
      p->~T();
   }

   void deallocate( pointer p, size_type nNum )
   {
      (void) nNum;
      delete[] p;
   }
};

Here is the error :

Error   1   error C2512: 'std::_Aux_cont' : no appropriate default constructor available    c:\XXX\AllocPowOf2.h    97

The code compiles correctly in debug mode in both Windows with VS2008 and Android with the Android NDK and eclipse.

Any idea ?


Solution

  • return new value_type[ OptimizeNbBytes( nNum * sizeof( value_type ), 32 ) ];
    

    Ignoring OptimizeNbBytes for now, you are newing up nNum * sizeof(value_type) value_types, which also calls value_type's constructor that many times.

    In other words, asked to allocate memory for 16 ints, you would allocate enough for 64 ints instead; not only that, but you were asked for raw memory, and instead ran constructors all over them, creating objects that will be overwritten by the container without being destroyed - and then the delete[] in deallocate will result in double destruction.

    allocate should allocate raw memory:

    return pointer(::operator new(OptimizeNbBytes( nNum * sizeof( value_type ), 32 )));
    

    and deallocate should deallocate the memory without running any destructor:

    ::operator delete((void*)p);