How does new handle alignment?

Started by
9 comments, last by Andrew Russell 18 years, 11 months ago
OK, I'm working on some fairly low level structure (C++ struct/class) manipulation type stuff. Essentially, I'm manually alocating a structure. The idea is to replicate the behaviour of C++ itself. Now, at the moment, I'm simply doing new char[] to alocate a buffer. However I don't know what the alignment of that would be. I noticed MSVC has an aligned_malloc function (sub-question: what is the GCC equvilent?), so I was going to move over to this. It then occured to me that I should see how operator new does it. Now operator new only takes one argument (size). How you'd magically generate the information to call aligned_malloc, which takes size and alignment, I don't understand. So question is: How does C++ handle alignment? Note: I know the required alignment of my structures already.
Advertisement
Quote:(sub-question: what is the GCC equvilent?)


POSIX 1003.1d defines the function posix_memalign (so named because an earlier, now obsolete function memalign found on many systems). Also, all glibc malloc implementations always return 8-byte aligned addresses.
What the standard says is:
Quote:
The pointer returned shall be suitably aligned so that it can be converted
to a pointer of any complete object type and then used to access the object or array in the storage
allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function).


basicly that means on an x86 system you could get mostly anything (though most implementations does return at least 4byte aligned addresses) and on something like 68k/PPC and other systems where odd addresses gives bus-errors for non byte types you are guaranteed to get an even address.

And that's it.

HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
OK, so new calls malloc (right?), which will always give an 8-byte aligned address (at least on glibc). So I could just call new char[whatever] or indeed new whatever, and the resultant pointer would be aligned to 8 bytes (nothing needs anything bigger, right?).

Basically, I just don't want to alocate something with new char[] and find that when I placement-new over the top of that, the buffer has a lower alignment that the struct I'm dropping on it.

So... is new char[] the equivelent of what C++ does anyway? Does it just always give you an 8-byte aligned pointer (effectivly making alignment a non-issue)?

And what about MSVC?
This should answer all your questions on portable alignment: Boost::Pool on Alignment

Essentially, new is guaranteed to properly align a block of size X to hold an array of any structure of size X or smaller. Thus, allocating 10 bytes with new would be aligned to hold anything 1 to 10 bytes in size, and it could be 2 objects of size 5 or 3 objects of size 3 etc. It gets somewhat tricky when you want to put different sizes in a single block, but it is still easily doable.

Also, boost has a templated value that will return the alignment requirements of any type.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
should work with any c++ compiler:
void* AlignedMalloc(size_t size,int byteAlign){	void *mallocPtr = malloc(size + byteAlign + sizeof(void*));	size_t ptrInt = (size_t)mallocPtr;	ptrInt = (ptrInt + byteAlign + sizeof(void*)) / byteAlign * byteAlign;	*(((void**)ptrInt) - 1) = mallocPtr;    return (void*)ptrInt;}void AlignedFree(void *ptr){	free(*(((void**)ptr) - 1));}
Ah, ok, I gotcha. From the boost thing:

Quote:Predicate 2: Any block of memory allocated as an array of characters through operator new[] (hereafter referred to as the block) is properly aligned for any object of that size or smaller


Which basically means that the memory allocation will round up to the nearest 2^N boundary when it allocates (up to 8 byte alignment?). Meaning an struct of 6 chars, which needs an alignment of 1, will just get an alignment of 8 (and bugger the wasted 2 bytes). An 8 byte alignment being suitable for 1 byte alignment data.

So I can use new char[] and safely drop anything on it, as long as it fits and it's properly aligned within itself? (I am thinking "yes")

Of course, this raises an interesting question - say my 6-char structure - if I made an array of 3 of them, would it use 18 bytes, or 24? Unless it knew that it only needs 1-byte alignment, it would have to be 24, right?

Or does that 6-byte struct get padded into 8 bytes by the compiler anyway?
Quote:Original post by Andrew Russell
OK, so new calls malloc (right?)


Not nessecaraly it's up to compiler vendor to-do so.

On a slightly unrelated note don't bother using new char, any form of implicit invocation of new will initialize memory, just invoke operator new & delete explicitly with the size required it will allocate a chunk of uninitialized memory e.g.:

#include <new>void* buf = ::operator new(sizeof(foo)); // allocates only//...foo* f = ::new(buf) foo(/* ... */);      // constructs only//...f->~foo();                               //destructs only//...::operator delete(buf);                  // deallocates only



Another alternative is to overload operators new/delete for a whole class hierarchy then the compiler will also give you the correct size to allocate also there is a special variant signature of delete for class or class hierarchies which the last parameter gives you the size of the actual memory passed including void pointer:

struct foo {  void* operator new(std::size_t n);  //...  // compiler automatically passes the size for you implicitly.  void operator delete(void* p, std::size_t n);
Ah great, thanks for that - I'll go with the first one in that case (implicit call to operator new). I don't have a class hirachy to put a member operator new in.
Quote:Original post by Andrew Russell
[...]So I can use new char[] and safely drop anything on it, as long as it fits and it's properly aligned within itself? (I am thinking "yes")
Yes

Quote:Of course, this raises an interesting question - say my 6-char structure - if I made an array of 3 of them, would it use 18 bytes, or 24? Unless it knew that it only needs 1-byte alignment, it would have to be 24, right?

Or does that 6-byte struct get padded into 8 bytes by the compiler anyway?
The structure must be properly padded by the compiler such that putting two of them with 0 bytes between will result in both being properly aligned if the first one is.

I don't know if char[x] must be properly aligned for an x-byte structure, but using 'new char[x]' will meet that requirement.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk

This topic is closed to new replies.

Advertisement