简体   繁体   中英

resize an array of pointers without memory leak

I have a pointer to an array of pointers-to-objects, and need to resize the array. I do realize this is a perfect time to use vectors, But I'm not permitted to do so. My code works, but I don't completely follow what I've written, and concerned i may have created memory leaks:

void foo (DataSet &add_data)
{
    if (sets == NULL)
    {
        sets = new DataSet*[1];
        sets[0] = &add_data;
    }
    else
    {
        DataSet **transfer;        
        transfer = new DataSet*[num_of_sets];       

        for (int i = 0; i < num_of_sets; i++) // Copy addresses?
            transfer[i] = sets[i];     

        delete [] sets; // Free the array.        
        sets = new DataSet*[num_of_sets + 1]; // Create new sets  

        for (int i = 0; i < num_of_sets; i++) // Copy back
            sets[i] = transfer[i];            

        sets[num_of_sets] = &add_data;        // Add the new set        
        delete [] transfer;
        transfer = NULL;
    }    
    num_of_sets++;
}

Why does Visual Studio throw an exception for:

for (int i = 0; i < num_of_sets; i++) // Copy addresses?
    *transfer[i] = *sets[i];

but not:

for (int i = 0; i < num_of_sets; i++) // Copy addresses?
    transfer[i] = sets[i];

But both code segments compile and run without fault in linux. This code should copy the pointers-to-objects. Is that what is happening with:

for (int i = 0; i < num_of_sets; i++) // Copy addresses?
    transfer[i] = sets[i];

And do I need to be concerned if I want to free these objects with say a remove function later?

*transfer[i] = *sets[i];

Does not copy addresses, like the other sample (without asterisks) does, it tries to dereference the uninitialized pointer elements of transfer and call operator= on DataSet objects on these addresses.

It's undefined behavior, that's why it appears to work under changed circumstances.

You do not need to allocate twice, just allocate once the final size:

    transfer = new DataSet*[num_of_sets + 1]; // Create new sets - final size

    for (int i = 0; i < num_of_sets; i++) // Copy addresses?
        transfer[i] = sets[i];

    delete [] sets; // Free the array.

    sets = transfer;

    sets[num_of_sets] = &add_data;        // Add the new set
    // now no need to delete[] transfer

That way you also get improved exception safety btw. - in your original code, you deleted the sets before allocating the new data to it - if that would throw std::bad_alloc , not only your object will become inconsistent (having a dangling sets ptr because you do not assign null to it after delete) but also the memory allocated to transfer would leak. If you allocate transfer directly to final size before delete[] sets , if that will throw, sets will stay intact and transfer will not leak (because it threw during allocation ie did not allocate).

Of course, make sure that you delete[] sets in the destructor (and maybe the pointers as well, in case your set is owning them).

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