Joel F Real men use unique_ptr | on passe par un allcoator custom. Mais premiere etape: savori aligner de la memoire ;0
Allons y :
Allocation bas niveau alignée
Sous pas mal de systeme, y a une fonction tte faites. Sinon, on va faire du pointeur stashing
Code :
- #if ( (defined _GNU_SOURCE) \
- || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)) \
- ) \
- && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0)
- #include <cstdlib>
- #include <cstring>
- #define SUPPORT_POSIX_MEMALIGN
- #endif
- void* allocate( std::size_t nbytes )
- {
- void *result;
- BOOST_STATIC_CONSTANT(std::size_t, align = 16 );
- #if defined(SUPPORT_POSIX_MEMALIGN)
- //////////////////////////////////////////////////////////////////////////////
- // POSIX systems use posix_memalign
- //////////////////////////////////////////////////////////////////////////////
- if(posix_memalign(&result, align, nbytes))
- {
- throw std::bad_alloc();
- result = 0;
- }
- #elif defined (_MSC_VER)
- //////////////////////////////////////////////////////////////////////////////
- // MSVC systems use _aligned_malloc
- //////////////////////////////////////////////////////////////////////////////
- if( !(result = _aligned_malloc(nbytes, align) ) )
- {
- throw std::bad_alloc();
- result = 0;
- }
- #else
- //////////////////////////////////////////////////////////////////////////////
- // Other systems do the funky pointer stashing
- //////////////////////////////////////////////////////////////////////////////
- void *base;
- BOOST_STATIC_CONSTANT(std::size_t, fix = ~(std::size_t(align-1)));
- if( !(base = ::malloc(nbytes+align+sizeof(void*))) )
- {
- throw std::bad_alloc();
- result = 0;
- }
- else
- {
- std::size_t ref = reinterpret_cast<std::size_t>(base)+sizeof(void*);
- std::size_t stashed = (ref & fix) + align;
- result = reinterpret_cast<void*>(stashed);
- reinterpret_cast<void**>(result)[-1] = base;
- }
- #endif
- return result;
- }
- void deallocate( void* ptr, std::size_t )
- {
- #if defined(SUPPORT_POSIX_MEMALIGN)
- //////////////////////////////////////////////////////////////////////////////
- // POSIX systems use free
- //////////////////////////////////////////////////////////////////////////////
- if(ptr) ::free(ptr);
- #elif (defined _MSC_VER)
- //////////////////////////////////////////////////////////////////////////////
- // MSVC systems use _aligned_free
- //////////////////////////////////////////////////////////////////////////////
- if(ptr)_aligned_free(ptr);
- #else
- //////////////////////////////////////////////////////////////////////////////
- // Other systems do the funky pointer stashing
- //////////////////////////////////////////////////////////////////////////////
- if(ptr) ::free( reinterpret_cast<void**>(ptr)[- 1] );
- #endif
- }
|
Allocator custom
Code :
- template<class T> struct aligned_allocator
- {
- ////////////////////////////////////////////////////////////////////////////
- // Internal typedefs
- ////////////////////////////////////////////////////////////////////////////
- typedef T value_type;
- typedef T* pointer;
- typedef T const* const_pointer;
- typedef T& reference;
- typedef T const& const_reference;
- typedef std::size_t size_type;
- typedef std::ptrdiff_t difference_type;
- template<class U> struct rebind { typedef aligned_allocator<U> other; };
- ////////////////////////////////////////////////////////////////////////////
- // Ctor/dtor
- ////////////////////////////////////////////////////////////////////////////
- aligned_allocator() {}
- template<class U> allocator(aligned_allocator<U> const& ) {}
- ~aligned_allocator() {}
- aligned_allocator& operator=(aligned_allocator const& ) { return *this; }
- ////////////////////////////////////////////////////////////////////////////
- // Address handling
- ////////////////////////////////////////////////////////////////////////////
- pointer address(reference r) { return &r; }
- const_pointer address(const_reference r) { return &r; }
- ////////////////////////////////////////////////////////////////////////////
- // Size handling
- ////////////////////////////////////////////////////////////////////////////
- size_type max_size() const { return size_type(~0); }
- ////////////////////////////////////////////////////////////////////////////
- // Object lifetime handling
- ////////////////////////////////////////////////////////////////////////////
- void construct(pointer p, const T& t)
- {
- p = new (p) value_type(t);
- }
- void destroy(pointer p) { p->~value_type(); }
- ////////////////////////////////////////////////////////////////////////////
- // Memory handling
- ////////////////////////////////////////////////////////////////////////////
- pointer allocate( size_type c, const void* = 0 ) const
- {
- void* ptr = allocate(c*sizeof(value_type));
- return reinterpret_cast<pointer>(ptr);
- }
- void deallocate (pointer p, size_type s) const
- {
- deallocate(p,s*sizeof(value_type));
- }
- };
|
Utilisation
Code :
- std::vector<float, aligned_allocator<float> > v(10);
|
Et voila
Note, l'alignement n'a de sens que sur des puissance de 2.
L'exercice est laissée au lecteur de rendre le aligned_allcoator template sur la valeur de l'alignement.
Sinon, tout est la : https://github.com/metascale/nt2 dans le module nt2::memory |