   Alignment when overloading new [C++]
  I'm writing a memory allocation class to be used for several "temporary" objects in my game. These objects only need to exist for a single frame, and don't do anything meaningful in their destructors.My class is designed to have a fixed size heap and an index of the first unused byte in the heap. Allocations increment the index, and at the end of the frame I clear the heap by resetting the index to 0 (the objects are "leaked", but the memory is reused).What I'm not quite sure about, is how exactly I should be aligning these allocations. I've been warned that you should only use placement new if you know how to handle alignment, so I'm kind of uneasy.At the moment, I'm aligning the allocations to 4-byte boundaries like so:namespace {const static uint gs_Alignment = sizeof(int);}The allocation code://m_Heap is a std::vector<char>, m_Usage is an unsigned int.CTempHeap::CTempHeap( size_t heap ){m_Heap.resize( heap );m_Usage = 0;}void* CTempHeap::Alloc( size_t size ){uint startByte = m_Usage;startByte = ((startByte+(gs_Alignment-1))/gs_Alignment)*gs_Alignment;uint newUsage = startByte + size;if( newUsage >= m_Heap.size() )return NULL;m_Usage = newUsage;return &m_Heap[startByte];}void CTempHeap::Clear(){m_Usage = 0;}void* CTempObj::operator new( size_t size, CTempHeap& w ){void* p = w.Alloc( size );if( !p )//TODO - use the new handlerthrow std::bad_alloc();return p;}Usage:CTempHeap heap( 1024 );//1kb heapCTempObj* pTest = new(heap) CTempObj;pTest = 0;heap.Clear();[Edit:] I just realised that my code is aligning the offset from the beginning of my buffer, not the actual memory address! I'll have to fix this.[Edited by - Hodgman on May 6, 2009 12:58:42 AM]
  Proper alignment for objects is platform and data type dependent. In general, align primitives to a multiple to their size and align classes to a multiple of the size of their largest primitive. So general case means a multiple of the size of the largest primitive. Depending on your platform, not using proper alignment will either be somewhat slower (ex: on x86) or will crash your program (especially on finicky embedded systems).   ;  Wouldn't it be possible to put those instances on the stack instead?   ;Quote:Original post by SiCrane...So general case means a multiple of the size of the largest primitive. Depending on your platform, not using proper alignment will either be somewhat slower (ex: on x86) or will crash your program (especially on finicky embedded systems).So assuming I had some cool meta-programming/reflection type stuff, I could do:FindAlignment( obj ): if obj is primitive, then  return sizeof(obj) align = 1 for each member of obj  if member is class, align = max( align, FindAlignment(member) )  else,align = max( align, sizeof(member) ) return alignQuote:Original post by visitorWouldn't it be possible to put those instances on the stack instead?Unfortunately there's an unpredictable number of different types of objects (polymorphic) required for any frame. This is actually for a multi-threading system - these temporary objects are actually structures representing delayed function calls to be scheduled on the next frame.   ;  I've been using a hack like this in an "obstack" allocator:#define alignof(type) (sizeof(struct { char p; type q; }) - sizeof(type))void *align_ptr(void *ptr, ptrdiff_t align) {ptr += align - 1;return (void *) ((intptr_t) ptr & -align));}This seems to work fairly well in practice, though there obviously isn't any fully portable solution.   ;  According to the C++ standard, operator new must return memory properly aligned for any type.Yes, that sucks, but that's the way it is.If you want to know alignment of some type, just do std::alignment_of<T>::value.To know "worse" alignment, just do std::alignment_of<some_union_of_all_basic_types>:value.Note that on x86, worse alignment is typically 8 or 16, depending whether you take into account __m128 and stuff like that or not.   ;  For people not using a time-tunneling modem to post from the future like loufoque does, alignment_of can be found in boost's type_traits.hpp or type_traits/alignment_of.hpp headers or if your compiler supports TR1, in the TR1 header type_traits in the std::tr1 namespace.   ;Quote:Original post by SiCraneFor people not using a time-tunneling modem to post from the future like loufoque does, alignment_of can be found in boost's type_traits.hpp or type_traits/alignment_of.hpp headers or if your compiler supports TR1, in the TR1 header type_traits in the std::tr1 namespace.Does the new standard come with guidelines as to how to use it to safely align pointers?As I recall previous C/C++ standards gave few guarantees about what a pointer cast to an integer actually represented. And one might easily imagine byzantine architectures where intentionally misaligned pointers are used to signal something or other (I believe odd addresses are used to indicate Thumb-mode code on ARM processors for instance.)Though at the end of the day I suppose malloc must be able to infer the proper alignment of a type from the size alone. Well, I suppose an intermediate cast to a void * pointer couldn't hurt at least.   ;  Thanks for all the info guys, it's big help.Quote:Original post by SiCraneFor people not using a time-tunneling modem to post from the futureYou're so harsh SiCrane, but it makes me laugh ;D   ;  This is machine dependant. A lot of machines will throw a "bus error" if you don't align your data correctly. I believe that Intel processors will load and store data anyway with some performance hit. At least that's what used to happen. I'm not sure about the newer processors. If you align to 8 bytes you are fairly safe for stuff up to double precision. If you don't use doubles you can align to 4. I have noticed malloc aligns to 8 on a lot of machines so that's what I would tend to start with although you might waste some space in some cases. You can always go all out and make it a parameter. By the way I have a library of about 10 different memory allocators for doing various things like you are up to. It's well worth the effort.  The performance gain can be huge!