Распределение памяти при создании объекта C ++ - PullRequest
5 голосов
/ 30 января 2012

Другой размер выделения памяти наблюдается при создании объекта в классе C ниже,

class C {
 int i;
 int j;
};

void f() {
 C *c = new C;
 C *c2 = new C[2];
 C (*c3)[2] = new C[2][2];
}

c выделяется 8 байтами;

c2 выделяется 8 * 2 + 4 байта;

c3 выделяется 8 * 2 * 2 + 4 байта.

Почему c2 и c3 получают еще 4 байта?

Ответы [ 3 ]

8 голосов
/ 30 января 2012

Помните, что C ++ разделяет выделение памяти и выражение объекта .Выражение new-array-new T * p = new T[N]; выделяет достаточно памяти для N объектов и для создания этих объектов.С другой стороны, delete[] p; должен вызвать деструктор всех этих элементов и затем освободить память.

При выделении и освобождении памяти обрабатывается платформой, и свободная память достаточно хорошо идентифицируется для ОСПо одному значению указателя, создание и уничтожение объектов более сложны.Количество реальных объектов должно храниться где-то, и с этой целью стандарт позволяет реализации C ++ запрашивать больше памяти, чем N * sizeof(T).Это правда, что указатель p всегда будет указывать на начало массива N объектов, но p не обязательно должен быть тем же указателем, который был возвращен базовым распределителем памяти.(На самом деле, p гарантированно будет точно значением базового результата выделения, смещенным на избыточный объем памяти.)

Детали полностью оставлены на усмотрение реализации.Некоторые платформы предоставляют дополнительные гарантии;например, Itanium ABI (который называет дополнительные данные "массив cookie") говорит, что память для new T[N] будет распределена следующим образом:

+- alignof(T) --+-- sizeof(T) --+-- sizeof(T) --+-- sizeof(T) --+-- ...
| ***** [8B: N] |  1st element  |  2nd element  |  3rd element  |  .....
+---------------+---------------+---------------+---------------+-- ...
A               A
|               |_ result of "new T[N]"
|
|_ value returned "operator new[]()"
4 голосов
/ 30 января 2012

Из стандарта (раздел [expr.mew]):

A new-expression передает количество пространства, запрошенное для функции выделения, в качестве первого аргумента типа std::size_t. Этот аргумент должен быть не меньше размера создаваемого объекта; он может быть больше размера создаваемого объекта, только если объект является массивом.

Очевидно, что стандарт ожидает, что некоторая дополнительная информация будет храниться в динамически распределенном массиве.

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

(Подсказка: исправьте вашу программу, чтобы она не пропускала память)

3 голосов
/ 30 января 2012

Многие компиляторы используют 4 байта перед указателем, возвращаемым из new [], для хранения количества фактически выделенных объектов. Все это зависит от реализации, и важно помнить, что арифметика указателей, которая выводит вас за пределы объема выделенной памяти, приводит к неопределенному поведению

...