Необычное использование нового в историческом коде. Что это значит? - PullRequest
5 голосов
/ 13 января 2011

Я просто портирую какой-то старый код:

#define NewArrayOnHeap(TYPE, COUNT, HEAP, NEWPTR, ERROR) \
((*(NEWPTR) = new ( #TYPE "[" #COUNT "]", __alignof(TYPE), (HEAP), &hr, (ERROR)) TYPE[COUNT] ), hr)

Похоже, оригинал должен был определить собственный магический оператор new.Мне интересно это использование.

Пример использования

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 */");
}

Когда я использую g++ -E, чтобы получить вывод препроцессора, это:

int main()
{
    double* ptr;
    HRESULT hr;

    hr = ((*(ptr) = new ( "double[ 10 ]", __alignof(double), (NULL), &hr, ("Help")) double[10] ), hr);
}

Это выглядит немногобольше похоже на placement new.

Но теперь это перегруженный новый вызов (с некоторыми непонятными параметрами, пятипараметрическим вызовом new), или запятые здесь - оператор запятой, и таким образом он уменьшается("Help") (что не имеет смысла).

Было ли new исторически (или даже сейчас) разрешено иметь более двух параметров, (size, hint)?

Любая помощь по декодированиюбудет оценена.

Ответы [ 2 ]

7 голосов
/ 13 января 2011

Раздел, на который вы хотите посмотреть, - §5.3.4 / 11-12, перефразированный здесь:

Синтаксис нового размещения используется для предоставления дополнительных аргументов функции размещения. Если используется, разрешение перегрузки выполняется для вызова функции, созданного путем сборки списка аргументов, состоящего из объема запрошенного пространства (первый аргумент) и выражений в части нового размещения нового выражения (второй и последующие аргументы) , Первый из этих аргументов имеет тип size_t, а остальные аргументы имеют соответствующие типы выражений в новом размещении.

[Пример:
- new T приводит к вызову оператора new (sizeof (T)),
- new (2, f) T приводит к вызову оператора new (sizeof (T), 2, f),
- new T [5] приводит к вызову оператора new, и
- new (2, f) T [5] приводит к вызову оператора new [] (sizeof (T) * 5 + y, 2, f).]

Таким образом, ваш макрос для правильного использования требует, чтобы где-то была определена перегрузка operator new, подобная:

void* operator new[](size_t, const char*, size_t, void*, HRESULT*, const char*);

Что, я подозреваю, использует информацию, предоставленную ему, для выделения памяти (потенциально из предварительно выделенного источника), которая удовлетворяет требованиям выравнивания, при этом регистрируя это распределение и предоставляя пользовательское сообщение об ошибке, если распределение не может быть выполнено.

Лично я нахожу это грубым. :)


Типичный оператор "размещения нового", на который вы ссылаетесь, определен в <new> и является просто еще одной перегрузкой, которая принимает void* и возвращает ее в качестве результата выделения.

3 голосов
/ 13 января 2011

Я предполагаю, что это новое размещение, и что все 5 являются аргументами перегрузки.В моей неверной интерпретации один из аргументов - &hr, который является кодом ошибки и затем используется в качестве второго аргумента для operator,, чтобы предоставить это в качестве значения результата.

Я не думаю, что вашиспользование макроса является правильным, в частности, я считаю, что NEWPTR предназначен для адреса фактического указателя для инициализации, то есть вызывающий код должен быть:

hr = NewArrayOnHeap(double, 10, heap, &ptr, "Help");

, что может привести к расширению:

hr = ((*(&ptr) = new ( "double[ 10 ]", __alignof(double), (NULL), &hr, ("Help")) double[10] ), hr);

Без дополнительного & левая и правая части внутреннего назначения не будут совпадать по типу: *(ptr) - это double, while the result of placement new would be a double * `.

...