为什么在动态数组上以特定方式调用'delete'不起作用?

Why does calling 'delete' in a specific way on a dynamic array not work?

本文关键字:调用 delete 不起作用 方式 动态 数组 为什么      更新时间:2023-10-16

我想知道为什么这段代码不工作:

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 ?

动态数组不仅仅是一个元素序列。它还包含有关数组大小的信息。而且,分配器只知道一个内存块。因此,就像任何动态内存一样,您只能释放您分配的内存,而不能释放它的较小子集。

这就是为什么语言要求您只在从new[]表达式获得的指针上调用delete[],并且这是唯一释放该内存的方法。

简单的回答: 因为语言规范说您可以使用delete[]

更好的答案是: ,因为毕竟对于堆管理器来说,m_ppKeyValueList指向的数组是一个单一的大分配,而不是m_iCapacity连续的小分配,所以你只需要告诉它分配的块从哪里开始,它将作为一个整体释放它(如果需要的话,在调用单个析构函数之后);如果它将每个元素作为一个单独的分配到已分配的块列表中,这将是一个愚蠢的资源浪费(如果它使用位图,它可能没有足够的粒度来支持这个愚蠢的分配方案)。

因为new int[5]分配了一个足够大的连续块来容纳5个int。new int 5次分配5个小块,每个小块足够容纳一个int型。释放的数量必须等于分配的数量

Case 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;
}

回收:

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

然而,你的代码失败表明你没有"一个指向堆上对象的动态指针数组"。

Case 2: m_ppKeyValueList是堆上对象的动态数组
这里你的声明将是SomeType * m_ppKeyValueList;的形式,而不是一块一块地分配,你的分配和释放采取了一个更简单的形式:

分配:

m_ppKeyValueList = new SomeType[m_iCapacity];

回收:

delete[] m_ppKeyValueList;

:
您的分配和回收需要在数量和形式上相互匹配。如果你用new分配一些东西,你需要用delete销毁它。如果您使用new[]分配它,则需要使用delete[]销毁它。