Почему невозможно получить доступ к размеру нового массива [] d? - PullRequest
19 голосов
/ 09 марта 2010

Когда вы выделяете массив с помощью new [], почему вы не можете узнать размер этого массива по указателю? Это должно быть известно во время выполнения, иначе delete [] не будет знать, сколько памяти освободить.

Если я что-то упустил?

Ответы [ 4 ]

15 голосов
/ 09 марта 2010

В типичной реализации размер динамического блока памяти как-то сохраняется в самом блоке - это правда. Но нет стандартного способа доступа к этой информации. (Реализации могут предоставлять специфические для реализации способы доступа к нему). Вот как у malloc/free, вот как у new[]/delete[].

Фактически, в типичной реализации необработанные выделения памяти для вызовов new[]/delete[] в конечном итоге обрабатываются некоторой парой malloc/free -подобной реализации, что означает, что delete[] на самом деле не нужно заботиться о том, сколько памяти для освобождения: он просто вызывает этот внутренний free (или как его там называют), который позаботится об этом.

Что нужно знать delete[], так это то, сколько элементов разрушает в ситуациях, когда тип элемента массива имеет нетривиальный деструктор. И вот о чем ваш вопрос - количество элементов массива , а не размер блока (эти два значения не совпадают, блок может быть больше, чем на самом деле требуется для самого массива). По этой причине количество элементов в массиве обычно также сохраняется внутри блока с помощью new[], а затем извлекается с помощью delete[] для правильного уничтожения элементов массива. Также нет стандартных способов доступа к этому номеру.

(Это означает, что в общем случае типичный блок памяти, выделенный new[], будет независимо хранить одновременно и размер физического блока в байтах и количество элементов массива. Эти значения сохраняются различными уровнями механизма выделения памяти C ++ - необработанным распределителем памяти и самим new[] соответственно - и никак не взаимодействуют друг с другом).

Однако обратите внимание, что по указанным выше причинам количество элементов массива обычно сохраняется только тогда, когда тип элемента массива имеет нетривиальный деструктор. То есть этот счет не всегда присутствует. Это одна из причин, по которой предоставление стандартного способа доступа к этим данным неосуществимо: вам придется либо хранить их всегда (что тратит память), либо ограничивать их доступность типом деструктора (что сбивает с толку).

Чтобы проиллюстрировать вышеизложенное, при создании массива int s

int *array = new int[100];

размер массива (т. Е. 100) равен , а не , обычно хранится new[], поскольку delete[] не заботится об этом (int не имеет деструктора). Физический размер блока в байтах (например, 400 байтов или более) обычно сохраняется в блоке необработанным распределителем памяти (и используется обработчиком необработанной памяти, вызываемым delete[]), но может легко оказаться равным 420 по какой-то конкретной причине реализации. Таким образом, этот размер в принципе бесполезен для вас, так как вы не сможете получить точный исходный размер массива из него.

7 голосов
/ 09 марта 2010

Скорее всего, вы можете получить к нему доступ, но это потребует глубоких знаний вашего распределителя и не будет переносимым. Стандарт C ++ не определяет , как реализации хранят эти данные, поэтому нет единого способа их получения. Я считаю, что это не определено, потому что разные распределители могут хранить его по-разному в целях эффективности.

5 голосов
/ 09 марта 2010

Это имеет смысл, так как, например, размер выделенного блока не обязательно должен быть таким же, как размер массива. В то время как верно , что new[] может хранить количество элементов (вызывая каждый элемент деструктор), это не обязательно, так как это не потребуется для пустого деструктора. Также нет стандартного способа ( C ++ FAQ Lite 1 , C ++ FAQ Lite 2 ) для реализации, где new[] хранит длину массива, так как у каждого метода есть свои плюсы и минусы.

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

3 голосов
/ 09 марта 2010

Проще говоря, стандарт C ++ не требует поддержки для этого. Возможно, что если вы достаточно знаете о внутренностях вашего компилятора, вы сможете выяснить, как получить доступ к этой информации, но это будет обычно считаться плохой практикой. Обратите внимание, что может быть различие в расположении памяти для массивов, выделенных в куче, и массивов, выделенных в стеке.

Помните, что по сути то, о чем вы здесь говорите, это также массивы в стиле C - даже если new и delete являются операторами C ++ - и поведение наследуется от C. Если вы хотите массив C ++ " "такого размера, вы должны использовать STL (например, std :: vector, std :: deque).

...