I'm overloading operator new
, but I recently hit a problem with alignment. Basically, I have a class IBase
which provides operator new
and delete
in all required variants. All classes derive from IBase
and hence also use the custom allocators.
The problem I'm facing now is that I have a child Foo
which has to be 16-byte aligned, while all others are fine when aligned to 8-byte. My memory allocator however aligns to 8-byte boundaries only by default, so now the code in IBase::operator new
returns an unusable piece of memory. How is this supposed to be solved correctly?
I can simply force all allocations to 16 bytes, which will work fine until a 32-byte aligned type pops up. Figuring out the alignment inside operator new
doesn't seem to be trivial (can I do a virtual function call there to obtain the actual alignment?) What's the recommended way to handle this?
I know malloc
is supposed to return a piece of memory which is suitably aligned for everything, unfortunately, this "everything" doesn't include SSE types and I'd really like to get this working without requiring the user to remember which type has which alignment.
This is a possible solution. It will always choose the operator with the highest alignment in a given hierarchy:
It's based on the dominance rule: If there is an ambiguity in lookup, and the ambiguity is between names of a derived and a virtual base class, the name of the derived class is taken instead.
Questions were risen why
DeAllocator<I>
inheritsDeAllocator<I / 2>
. The answer is because in a given hierarchy, there may be different alignment requirements imposed by classes. Imagine thatIBase
has no alignment requirements,A
has 8 byte requirement andB
has 16 byte requirement and inheritsA
:Alignment<16>
andAlignment<8>
both expose anoperator new
. If you now saynew B
, the compiler will look foroperator new
inB
and will find two functions:Thus, this would be ambiguous and we would fail to compile: Neither of these hide the other one. But if you now inherit
Alignment<16>
virtually fromAlignment<8>
and makeA
andB
inherit them virtually, theoperator new
inAlignment<8>
will be hidden:This special hiding rule (also called dominance rule) however only works if all
Alignment<8>
objects are the same. Thus we always inherit virtually: In that case, there is only oneAlignment<8>
(or 16, ...) object existing in any given class hierarchy.mixins are the right approach, however overloading operator new is not. This will accomplish what you need:
Prints
For gcc, use
Note that there is automatic selection of the largest alignment, and this works for objects placed on the stack, ones that are new'd, and as members of other classes. Nor does it add any virtuals and assuming EBCO, no extra size to the class (outside of the padding needed for the alignment itself).
Using Visual Studio Express 2010, the above example does not seem to work with new:
will give __align_of(c) == 4 (to be expected I presume), but the address of a first member of CacheAlign isn't aligned as requested either.
Not a recent question, but if I understand the OP correctly, he has classes that are children of a parent class which define the allocator & deallocator, and can all require specific alignment. What's wrong with having a simple new that calls some private allocator that does the actual work and receives an alignment argument - a generic version with default alignment in the parent class that's inherited or overloaded with a version that specifies the correct alignment?