Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unusual use of new in historical code. What does it mean?

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.

Example 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.

like image 716
Martin York Avatar asked Jan 13 '11 20:01

Martin York


2 Answers

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.

like image 141
GManNickG Avatar answered Sep 20 '22 16:09

GManNickG


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 adouble*`.

like image 25
David Rodríguez - dribeas Avatar answered Sep 21 '22 16:09

David Rodríguez - dribeas