Почему вызов 'delete' определенным образом для динамического массива не работает? - PullRequest
2 голосов
/ 28 сентября 2011

Мне интересно, почему этот код не работает:

void KeyValueList::Release()
{
//(m_ppKeyValueList is a dynamic array of pointers to objects on the heap)
    if (m_ppKeyValueList) {
        for (int i = 0; i < m_iCapacity; ++i) {
            if (m_ppKeyValueList[i]) {
                delete m_ppKeyValueList[i];
            }
        }
        /*delete[] m_ppKeyValueList;*/
        for (int i = 0; i < m_iCapacity; ++i) {
            delete (m_ppKeyValueList + i);
        }
    }
}

Почему мы не можем перебрать динамический массив и delete таким образом?

Ответы [ 4 ]

4 голосов
/ 28 сентября 2011

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

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

3 голосов
/ 28 сентября 2011

Простой ответ: , потому что языковые спецификации говорят, что вы делаете это с delete[].

Лучший ответ: , потому что, в конце концов, для менеджера кучи массив, обозначенный m_ppKeyValueList, представляет собой одно большое выделение, а не m_iCapacity последовательное выделение, поэтому вы просто сообщить ему, где начинается выделенный блок, и он освободит его целиком (после вызова, если необходимо, отдельных деструкторов); если бы он хранил каждый элемент как отдельное выделенное распределение в выделенных списках блоков, это было бы глупой тратой ресурсов (и если бы он использовал для этого растровое изображение, у него, вероятно, не было бы достаточно детализации для поддержки этой глупой схемы распределения).

0 голосов
/ 28 сентября 2011

Случай 1 : m_ppKeyValueList - это " динамический массив указателей на объекты в куче "
В этом случае вам нужно удалить m_ppKeyValueList по частям. Если это именно то, что вы имели в виду, ваша декларация будет иметь вид SomeType ** m_ppKeyValueList; Ваше распределение и освобождение должно быть таким:

Распределение:

m_ppKeyValueList = new SomeType*[m_iCapacity];
for (int i = 0; i < m_iCapacity; ++i) {
  m_ppKeyValueList[ii] = new SomeType;
}

Deallocation:

for (int i = 0; i < m_iCapacity; ++i) {
  delete m_ppKeyValueList[ii];
}
delete[] m_ppKeyValueList;

Однако из-за того, что ваш код дает сбой, можно предположить, что у вас нет «динамического массива указателей на объекты в куче».

Случай 2 : m_ppKeyValueList - это динамический массив объектов в куче
Здесь ваша декларация будет иметь вид SomeType * m_ppKeyValueList; Вместо того, чтобы выделять этот фрагмент по частям, ваше выделение и освобождение принимают гораздо более простую форму:

Распределение:

m_ppKeyValueList = new SomeType[m_iCapacity];

Deallocation:

delete[] m_ppKeyValueList;

Итог :
Ваше распределение и освобождение должны соответствовать друг другу по количеству и форме. Если вы выделите что-то с помощью new, вам нужно уничтожить это с помощью delete. Если вы наделите его new[], вам нужно уничтожить его delete[].

0 голосов
/ 28 сентября 2011

Поскольку new int[5] выделяет один непрерывный блок, достаточно большой, чтобы вместить 5 дюймов. new int 5 раз выделяет 5 маленьких блоков, каждый из которых достаточно большой, чтобы содержать один int. Количество освобождений должно равняться количеству выделений.

...