简体   繁体   中英

I need to resize an array of pointers

Lets say i want to resize an array of int pointers, i have a function that looks like this

    template<typename T>
static void Resize(T* arr, UINT oldsize, UINT newsize) {
    T* ret = new T [newsize];
    memcpy(ret, arr, sizeof(arr[0]) * oldsize);
    delete[] arr;   
    arr = ret;
};

The problems begin when i try and resize an array of elements that were created with the "new" keyword (even though the data itself inside the class is POD) because the delete[] triggers their deconstructor which then leaves the new array with pointers to objects that dont exist anymore. So.. even though the objects were created with "new", cant i just use the free command to get rid of the old array? or somehow delete the array without triggering the deconstructor of each member?

Use a std::vector .


EDIT : by popular demand, an explanation of why the OP's code does not work .

The code:

template<typename T>
static void Resize(T* arr, UINT oldsize, UINT newsize) {
    T* ret = new T [newsize];
    memcpy(ret, arr, sizeof(arr[0]) * oldsize);
    delete[] arr;   
    arr = ret;
};

Here arr is a pointer passed by value. Assigning to arr at the end only updates the local copy of the actual argument. So after this the actual argument, in the calling code, points to an array that has been delete d, whith pretty catastrophic result!

It could be sort of rescued by passing that pointer by reference :

template<typename T>
static void Resize(T*& arr, UINT oldsize, UINT newsize) {
    T* ret = new T [newsize];
    memcpy(ret, arr, sizeof(arr[0]) * oldsize);
    delete[] arr;   
    arr = ret;
};

But this is still pretty fragile code.

For example, the caller needs to keep track of the array size.

With a std::vector called a , the resize call would instead look like

a.resize( newSize )

and in contrast to the DIY solution, when newSize is larger, those extra elements of the vector are nulled (which is a bit safer than leaving them as indeterminate values).

A std::vector can be indexed just like a raw array. See your C++ textbook about more details of how to use it. If you don't already have a C++ textbook, do get one: for most people it's just an impractical proposition to learn C++ from articles and Q/A on the web.

For what it's worth, what you're trying to do isn't a terribly bad thing, and there are times it makes sense, but it's simply not supported by the interface provided by new and delete (or new[] and delete[] ). As others have said, it is supported by malloc , free , and realloc (with the caveat that realloc will copy the pointer values on reallocation, but won't guarantee that the pointers in the new area are initialized to anything useful, like NULL ).

So, without further ado, the easiest answer that will work for almost everybody is to use a std::vector<int> instead of trying to manage the memory yourself. The vector has the ability to resize, and when it does it will copy things that need copying. std::vector exists to provide a "resizable array" and manage the memory for you. Actually, if you want a container of pointers, you're best off using either a std::vector<std::unique_ptr<T>> / std::vector<std::shared_ptr<T>> (in C++11) or something from Boost Pointer Container .

For what it's worth, the original STL did not use new[] or delete[] to implement std::vector<T> . Often, the operating system gives far more memory than you ask for. For instance, if I try to malloc 16 bytes, the block I get back may well be 1024 bytes. I can use that to store four 32 bit integers. When I run out of space, I may ask for 32 bytes, and get a different block of 1024 bytes, which I can copy my four integers to. But why go through the trouble of asking for a new block to hold my integers, when the original block was actually large enough to begin with? Unfortunately, new[] and delete[] don't provide a way to say "give me a block that's at least this large, and by the way here's a block that might already be big enough." realloc kind of does. Facebook Folly includes a std::vector -like container that doesn't use new[] or delete[] (note that it doesn't use realloc either, because that usually won't work with containers of objects; instead it uses malloc and the non-standard function malloc_usable_size ), and Firefox goes through the trouble to manage memory in a similar manner.

Even so, I would discourage trying to get tricky. std::vector has a lot of satisfied users.

I think that making all elements in array point to NULL before deleting should do the job. But if you can use STL then std::vector would make your life much easier (as Alf suggested :P).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM