Почему оператор new [] выделяет память под размер массива? - PullRequest
0 голосов
/ 27 апреля 2018

Я реализовывал распределитель стека и перегрузил operator new[] для определенного класса, чтобы использовать мой собственный распределитель. Затем я заметил, что operator new[] выделил память для количества элементов в выделенном массиве.
Так, например:

test_class* test_arr = new test_class[5];

запрашивает 8 байтов + 5 * sizeof (test_class) от моего распределителя, и в первых 8 байтах он хранит размер массива, а именно 5 в данном случае.

Почему он это делает? Работа моего распределителя заключается в том, чтобы отслеживать количество выделенной памяти. Для этой части это не имеет смысла, не так ли? Так какой смысл? Кроме того, могу ли (или не должен?) Я как-то "выключить это"?

Ответы [ 2 ]

0 голосов
/ 28 апреля 2018

Когда вы пишете p = new T[N] в своем коде, компилятор генерирует код, который вызывает operator new[], чтобы выделить достаточно памяти для N объектов типа T плюс любую необходимую для учета информацию. Когда вы впоследствии вызываете delete[] p, компилятор вызывает деструктор для каждого из N элементов в массиве, на который указывает p, затем вызывает operator delete[], чтобы освободить память, полученную из operator new[].

Но N не всегда имеет одинаковое значение. Вы можете сделать p = new T[3]; delete[] p; p = new T[4]; delete[] p;, и каждый из двух удалений будет запускать разное количество деструкторов.

Чтобы вызвать правильное количество деструкторов, где-то должна быть записка, в которой записано, сколько объектов в массиве указывает на p. Эта заметка обычно хранится в той части памяти, которую компилятор получил от вызова operator new[]. Вот почему ему нужно дополнительное место.

Это типичная реализация в наши дни, но компилятор не обязан делать это таким образом. Например, по крайней мере одна ранняя реализация хранила отдельную таблицу значений указателей и количества деструкторов.

Кроме того, многие реализации не используют дополнительные издержки для типов, которые не имеют деструкторов. Так что int *p = new int[3] просто позвонит operator new(3*sizeof(int), а delete[] p просто позвонит operator delete(p).

0 голосов
/ 27 апреля 2018

Скорее всего new T[N] запросит указатель p на память размером sizeof(size_t) + N * sizeof(T) байтов, сохранит N в первых sizeof(size_t) байтах, а затем вернет (T*)(((size_t*)p)+1) пользователю (так что первый T находится в возвращенном указателе.)

Затем delete[] возьмет указанный указатель, посмотрит на *(p-sizeof(size_t)), чтобы увидеть, сколько объектов нужно уничтожить, уничтожить их и передать ((size_t*)p)-1 базовому распределителю, который будет освобожден.

...