Freeing last element of a dynamic array

…衆ロ難τιáo~ 提交于 2019-12-08 10:09:07

问题


I have

int * array=new int[2];

and I would like to free the memory of the last element, thus reducing the allocated memory to only 1 element. I tried to call

delete array+1;

but it gives error

*** glibc detected *** skuska: free(): invalid pointer: 0x000000000065a020 *

Can this be done in C++03 without explicit reallocation?

Note: If I wanted to use a class instead a primitive datatype (like int), how can I free the memory so that the destructor of the class is called too?

Note2: I am trying to implement vector::pop_back


回答1:


Don't use new[] expression for this. That's not how vector works. What you do is allocate a chunk of raw memory. You could use malloc for this, or you could use operator new, which is different from the new expression. This is essentially what the reserve() member function of std::vector does, assuming you've used the default allocator. It doesn't create any actual objects the way the new[] expression does.

When you want to construct an element, you use placement new, passing it a location somewhere in the raw memory you've allocated. When you want to destoy an element, you call its destructor directly. When you are done, instead of using the delete[] expression, you use operator delete if you used operator new, or you use free() if you used malloc.

Here's an example creating 10 objects, and destoying them in reverse order. I could destroy them in any order, but this is how you would do it in a vector implementation.

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 would be implemented by simply calling the destructor of the last element, and decrementing the size member variable by 1. It wouldn't, shouldn't (and couldn't, without making a bunch of unnecessary copies) free any memory.




回答2:


There is no such option. Only way to resize array is allocate new array with size old_size - 1, copy content of old array and then delete old array.

If you want free object memory why not create array of pointers?

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

// ...

delete arr[size-1];



回答3:


std::vector::pop_back doesn't reallocate anything — it simply updates the internal variable determining data size, reducing it by one. The old last element is still there in memory; the vector simply doesn't let you access it through its public API. *

This, as well as growing re-allocation being non-linear, is the basis of why std::vector::capacity() is not equivalent to std::vector::size().

So, if you're really trying to re-invent std::vector for whatever reason, the answer to your question about re-allocation is don't.


* Actually for non-primitive data types it's a little more complex, since such elements are semantically destroyed even though their memory will not be freed.




回答4:


Since you are using C++03, you have access to the std::vector data type. Use that and it's one call:

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

or

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

EDIT:

Why are you trying to re-invent the wheel? Just use vector::pop_back.

Anyway, the destructor is called on contained data types ONLY if the contained data type IS NOT a pointer. If it IS a pointer you must manually call delete on the object you want to delete, set it to nullptr or NULL (because attempting to call delete on a previously deleted object is bad, calling delete on a null pointer is a non-op), then call erase.



来源:https://stackoverflow.com/questions/13215645/freeing-last-element-of-a-dynamic-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!