I am just porting some old code:
#define NewArrayOnHeap(TYPE, COUNT, HEAP, NEWPTR, ERROR) \
((*(NEWPTR) = new ( #TYPE "[" #COUNT "]", __alignof(TYPE), (HEAP), &hr, (ERROR)) TYPE[COUNT] ), hr)
It looks like the original was supposed to define their own magical new
operator. I am curious about this usage.
int main()
{
void* heap = /* Don't know how to define this */
double* ptr;
HRESULT hr;
hr = NewArrayOnHeap(double, 10, heap, ptr, "Help /* Just guessing here */");
}
When I use g++ -E
to get the preprocessor output, it's:
int main()
{
double* ptr;
HRESULT hr;
hr = ((*(ptr) = new ( "double[ 10 ]", __alignof(double), (NULL), &hr, ("Help")) double[10] ), hr);
}
This looks slightly more like a placement new
.
But is this now an overloaded new call (with some funky parameters, a five parameter new
call), or are the commas here the comma operator and thus it gets reduced to ("Help")
(which wouldn't make sense).
Was new
historically (or even now) allowed to have more than two parameters, (size, hint)
?
Any help on decoding would be appreciated.
The section you want to look at is §5.3.4/11-12, paraphrased here:
The new-placement syntax is used to supply additional arguments to an allocation function. If used, overload resolution is performed on a function call created by assembling an argument list consisting of the amount of space requested (the first argument) and the expressions in the new-placement part of the new-expression (the second and succeeding arguments). The first of these arguments has type size_t and the remaining arguments have the corresponding types of the expressions in the new-placement.
[Example:
— new T results in a call of operator new(sizeof(T)),
— new(2,f) T results in a call of operator new(sizeof(T),2,f),
— new T[5] results in a call of operator new, and
— new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f).]
So your macro, to be used correctly, requires that somewhere there's an operator new
overload defined similar to:
void* operator new[](size_t, const char*, size_t, void*, HRESULT*, const char*);
Which I suspect uses the information given to it to allocate memory (potentially from a pre-allocated source) that satisfies alignment requirements, while logging this allocation and providing a custom error message if the allocation could not be made.
Personally, I find it gross. :)
The typical "placement new" operator you're referring to is defined in <new>
, and is just another overload that accepts a void*
and returns that as the allocation result.
My assumption is that it is placement new, and that all 5 are arguments to the overload. In my inerpretation, one of the arguments is &hr
, which is an error code and then is used as second argument to operator,
to provide that as a result value.
I don't think that your usage of the macro is correct, in particular I believe that NEWPTR
is intended to be the address of the actual pointer to initialize, that is, calling code should be:
hr = NewArrayOnHeap(double, 10, heap, &ptr, "Help");
which would make the expansion:
hr = ((*(&ptr) = new ( "double[ 10 ]", __alignof(double), (NULL), &hr, ("Help")) double[10] ), hr);
Without the extra &
, the left and right hand sides of the inner assignment would not match in type: *(ptr)
is a double, while the result of placement new would be a
double*`.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With