Skip to main content
GameDev.net gamedev.net
🔒 Locked

Global Placement New With Alignment

Started by ndwork Dec 1, 2008 at 10:53 PM 10 replies 1.8k views
Original Post
ndwork
ndwork
Thank you (anyone) for helping me out. I am coding in C++. This is my issue. I have a templated container class - it is essentially an array of the templated parameter. I would like the user to be able to pass in a construction argument that allows him/her to specify whether or not the memory that the class allocates is aligned. So I have code that looks like this: typedef enum{ ALIGN_THIS = 0 } ACV_INTERNAL_ENUM; void* operator new[]( std::size_t size, std::size_t alignment, ACV_INTERNAL_ENUM acvEnum ) throw(std::bad_alloc){ if( size==0 ) size=1; void* pMem = _aligned_malloc( size, alignment ); if(pMem) return pMem else throw std::bad_alloc(); } void operator delete[]( void* pMem, std::size_t alignment, ACV_INTERNAL_ENUM acvEnum ) throw(){ _aligned_free( pMem ); } template myClass::myClass( std::size_t nElements, bool iShouldAlign ){ if( iShouldAlign ){ m_data = new( 16, ALIGN_THIS ) T [nElements]; // Call my overloaded new } else { m_data = new T[nElements]; // Call regular new } } I have overloaded the new operator with the unused parameter 'acvEnum' to be able to specify when to use this version of operator new without overriding a standard version of new. I am failing at creating the destructor for myClass. The problem is that one cannot specifically call the corresponding overloaded delete. I need to call _aligned_free to correspond with _aligned_malloc, so the default version of delete will not work. The templated parameter T can be a primitive type, so it doesn't necessarily have a destructor; nor can I create a class that inherits from T. Any suggestions and thoughts would be greatly appreciated. Again, thank you all for your help. [Edited by - ndwork on December 3, 2008 1:02:55 PM]
ndwork
ndwork
A small reminder.
Guthur
Guthur
Could you maybe create an allocator/deallocator functor and make it one of the template parameters.

STL containers can use custom allocators, I believe, to do things like the this,
maybe it would be possible to write a custom allocator for say a std::vector to do what you want but its something i have very little knowledge of.

Just throwing out suggestions :)

EDIT: you would have to make the functor a template class i'd think, template template, yummy :p
Innovation not reiterationIf at any point I look as if I know what I'm doing don't worry it was probably an accident.
visitor
visitor
Don't know about the rest (is it absolutely necessary to overload new and delete?), but

Quote:

The templated parameter T can be a primitive type, so it doesn't necessarily have a destructor


This is not 100% true. This should be entirely valid:
#include <memory>template <class T>void foo(){    char* buf = new char[sizeof(T)];    T* p = new(buf) T;    //...    p->~T();    delete buf;}int main(){    foo<int>();}
ndwork
ndwork
Thank you very much for your reply - you are indeed correct. Primitive types do have destructors (or effectively have destructors).

The solution that I've come up with is as follows:


typedef enum{ ALIGN_THIS=0 } ACV_INTERNAL_ENUM;

void* operator new[]( std::size_t size, std::size_t alignment, ACV_INTERNAL_ENUM acvEnum ) throw(std::bad_alloc){
void* pMem = _aligned_malloc( size, alignment );
if(pMem) return pMem
else throw std::bad_alloc();
}
// Note: this is an incomplete overload of new. It was made simple for
// the purpose of this post.


void operator delete[]( void* pMem, std::size_t alignment, ACV_INTERNAL_ENUM acvEnum ) throw(){
_aligned_free( pMem );
}

template
void myDeallocate( T* ptr, const int &numElements ){
for( int i=0; i.~T();
_aligned_free( ptr );
}


//The class then allocates the memory using the overloaded new, and deallocates the memory using the function myDeallocate. Like this:


int main(){
p* = new( 16, ALIGN_THIS ) T [18];
// ...
myDeallocate( p, 18 );
}


This make the cardinal mistake of mixing new with free, but I don't see another way to solve the problem. Does anyone see a problem with the implementation the way I have it?



visitor
visitor
It looks like you could have something like this:

template <class T, unsigned Alignment>class AlignedAllocator{    public:        typedef T* pointer;        typedef const T* const_pointer;        typedef T& reference;        typedef const T& const_reference;        typedef T value_type;        typedef std::size_t size_type;        typedef std::ptrdiff_t difference_type;        template <class U>        struct rebind        {            typedef AlignedAllocator<T, Alignment> other;        };        pointer address(reference r)        {            return &r        }        const_pointer address(const_reference r)        {            return &r        }        size_type max_size()        {            return std::numeric_limits<size_type>::max();        }        void construct(const pointer ptr, const value_type& val)        {            new (ptr) T(val);        }        void destroy(const pointer ptr)        {            ptr->T::~T();        }        pointer allocate(const size_type n)        {            return (pointer)_aligned_malloc(n * sizeof(T), Alignment);        }        pointer allocate(const size_type n, const void * const)        {            return allocate(n);        }        void deallocate(pointer p, size_type )        {            _aligned_free(p);        }        bool operator==(const AlignedAllocator &) const        {            return true;        }        bool operator!=(const AlignedAllocator &) const        {            return false;        }};


And then simply use it with the STL, e.g:

std::vector<int, AlignedAllocator<int, 16> > vec;
ndwork
ndwork
Wow. Thank you very much for your help.

-Nick
Guthur
Guthur
Don't want to hijack the OP's thread, but visitor what is the following for:

template <class U>struct rebind{   typedef AlignedAllocator<T, Alignment> other;};


I'm glad you posted an allocator my c++ book says its too advanced a topic for it :|
Innovation not reiterationIf at any point I look as if I know what I'm doing don't worry it was probably an accident.
visitor
visitor
I actually ripped most of the code from boost allocators / standard draft :) This is supposed to be some sort of "template typedef", which probably might or might not get used somewhere for some purpose.

Quote:

3 The template class member rebind in the table above is effectively a
template typedef: if the name Allocator is bound to SomeAllocator,
then Allocator::rebind::other is the same type as SomeAllocator.


Actually I suspect it should be:

        template <class U>        struct rebind        {            typedef AlignedAllocator<U, Alignment> other;        };
Guthur
Guthur
Cool thanks, I really want to look into allocators more. The comparison operators seem alittle pointless though :p
Innovation not reiterationIf at any point I look as if I know what I'm doing don't worry it was probably an accident.
visitor
visitor
Quote:

--All instances of a given allocator type are required to be inter-
changeable and always compare equal to each other.


I'm not 100% sure it is all correct though, since this is my first time with custom allocators too.

It might be that boost has a suitable allocator.
Guthur
Guthur
Actually them being equal makes sense, should have realised that, an allocator for a type (and alignment in this case) should be the same.
Innovation not reiterationIf at any point I look as if I know what I'm doing don't worry it was probably an accident.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.