释放动态数组的最后一个元素

时间:2012-11-04 02:57:27

标签: c++ arrays dynamic delete-operator

我有

int * array=new int[2];

我希望释放最后一个元素的内存,从而将分配的内存减少到只有1个元素。我试着打电话给

delete array+1;

但是它给出了错误

  

*** glibc检测到*** skuska:   free():无效指针:0x000000000065a020 *

这可以在没有显式重新分配的情况下在C ++ 03中完成吗?

注意:如果我想使用类而不是原始数据类型(如int),我如何释放内存以便调用类的析构函数?

注意2:我正在尝试实施vector::pop_back

4 个答案:

答案 0 :(得分:4)

没有这样的选择。只调整数组大小的方法是分配大小为old_size - 1的新数组,复制旧数组的内容然后删除旧数组。

如果你想要自由对象内存,为什么不创建指针数组?

MyClass **arr = new MyClass*[size];
for(int i = 0; i < size; i++)
 arr[i] = new MyClass;

// ...

delete arr[size-1];

答案 1 :(得分:4)

请勿使用new[]表达式。这不是矢量的工作原理。你要做的是分配一大块原始内存。您可以使用malloc,或者可以使用operator new,这与新表达式不同。假设您使用了默认分配器,这基本上是reserve() std::vector成员函数的作用。它不会像new[]表达式那样创建任何实际对象。

当你想构造一个元素时,你使用placement new,将它传递给你已分配的原始内存中的某个位置。当你想要一个元素时,你可以直接调用它的析构函数。完成后,如果您使用delete[],则使用operator delete,或使用operator new时使用free(),而不是使用malloc表达式。< / p>

这是一个创建10个对象的示例,并以相反的顺序使它们失望。我可以按任何顺序销毁它们,但这就是你在矢量实现中的方法。

int main()
{
    void * storage = malloc(sizeof(MyClass) * 10);

    for (int i=0; i<10; ++i)
    {
        // this is placement new
       new ((MyClass*)storage + i) MyClass;
    }

    for (int i=9; i>=0; --i)
    {
        // calling the destructor directly
        ((MyClass*)storage + i)->~MyClass();
    }

    free(storage);
}

pop_back将通过简单地调用最后一个元素的析构函数,并将size成员变量减1来实现。它不会,也不会(并且不能,不会产生一堆不必要的副本)释放任何记忆。

答案 2 :(得分:3)

std::vector::pop_back不会重新分配任何内容 - 它只是更新确定数据大小的内部变量,将其减少一个。旧的最后一个元素仍然在记忆中;向量根本不允许您通过其公共API访问它。 *

增长重新分配是非线性的,是std::vector::capacity()不等同于std::vector::size()的基础。

所以,如果您因任何原因真的想重新发明std::vector,那么关于重新分配的问题的答案是


*实际上对于非原始数据类型来说,它有点复杂,因为即使它们的内存不会被释放,这些元素也会在语义上被破坏。

答案 3 :(得分:0)

由于您使用的是C ++ 03,因此您可以访问std::vector数据类型。使用它,这是一个电话:

#include <vector>
//...
std::vector<int> ary(3);
//...
ary.erase(ary.begin() + (ary.size() - 1));

#include <vector>
//...
std::vector<int> ary(3);
//...
ary.pop_back();

编辑:

你为什么要重新发明轮子?只需使用vector :: pop_back。

无论如何,只有在包含的数据类型不是指针的情况下才会对包含的数据类型调用析构函数。如果它是一个指针,你必须手动调用要删除的对象上的删除,将其设置为nullptrNULL(因为尝试在先前删除的对象上调用删除是错误的,在一个上调用delete空指针是非操作的,然后调用擦除。