0

In the example below, how do you make sure that the first array is deleted when the allocation for the second array fails? (With deliberate mistake of "-3" to cause an exception to be thrown for demonstration purposes).

#include <iostream>

using namespace std;

void func(int n1, int n2)
{
    int *array1 = new int[n1];
    cout << "alloc 1" << endl;
    int *array2 = new int[n2];
    cout << "alloc 2" << endl;
    // Something useful with these arrays goes here!
    delete[] array1;
    cout << "deleted 1" << endl;
    delete[] array2;
    cout << "deleted 2" << endl;
}

int main(int argc, char *argv[])
{
    try
    {
        func(10, -3);
    }
    catch(bad_alloc ex)
    {
        cout << "bad alloc" << endl;
    }
    return 0;
}

Or is "array1" deleted automatically?

Update

I can't use "std::vector" as I'm calling legacy functions, as well as my own functions that both use arrays.

A messy but functional solution:

void func(int n1, int n2)
{
    int *array1;
    int *array2;
    int v = 0;
    try
    {
        array1 = new int[n1];
        cout << "alloc 1" << endl;
        v = 1;
        array2 = new int[n2];
        cout << "alloc 2" << endl;
        // Something useful with these arrays goes here!
    }
    catch(bad_alloc ex)
    {
        cout << "bad alloc func" << endl;
        if (v == 1)
        {
            delete[] array1;
            cout << "deleted 1" << endl;
        }
        throw;
    }
    delete[] array1;
    delete[] array2;
}

int main(int argc, char *argv[])
{
    try
    {
        func(10, -3);
    }
    catch(bad_alloc ex)
    {
        cout << "bad alloc main" << endl;
    }
    return 0;
}
gornvix
  • 3,154
  • 6
  • 35
  • 74
  • 6
    Use a`std::vector` instead to guarantee that behavior. – πάντα ῥεῖ Aug 10 '19 at 19:13
  • 3
    or use smart pointers instead of raw pointers! – Klaus Aug 10 '19 at 19:15
  • `array1` is not deleted automatically. Yet another reason to use vector instead of arrays because then this hard work has been done for you. – john Aug 10 '19 at 19:24
  • `std::unique_ptr` if you can't use a vector for some reason – Aykhan Hagverdili Aug 10 '19 at 19:37
  • 1
    Possible duplicate of [What is meant by Resource Acquisition is Initialization (RAII)?](https://stackoverflow.com/questions/2321511/what-is-meant-by-resource-acquisition-is-initialization-raii) – ead Aug 10 '19 at 19:40
  • If your legacy functions take an `int*` you can use `vec.data()` to get that pointer. – Blastfurnace Aug 10 '19 at 19:46
  • what keeps you from checking right at the top of your ```func``` function whether the inputs are valid? And if the inputs are not valid, you can throw a ```bad_alloc``` exception yourself. – ozlsn Aug 10 '19 at 20:28
  • 1
    If you provide your own solution, then you should post it as an answer and see how people vote it compared to other answer... It is in fact messy. – Phil1970 Aug 11 '19 at 00:31

2 Answers2

7

Use a std::vector. It will automatically release the memory resource.

You can access the underlying pointer with the data() member function, so you can pass the data to legacy functions.

krisz
  • 2,686
  • 2
  • 11
  • 18
  • Oh, I heard a long time ago that the std library was buggy. So I try not to use it. I guess it's been fixed now? – gornvix Aug 10 '19 at 20:22
  • 2
    yes, it was buggy 20 years ago on Visual C++. But it works very well now... use strings & vectors, or C++ isn't that interesting to use as a language – Jean-François Fabre Aug 10 '19 at 20:33
0

You could put the second allocation inside a try … catch block:

void func(int n1, int n2)
{
    int* array1 = new int[n1];
    cout << "alloc 1" << endl;
    int* array2;
    try {
        array2 = new int[n2];
    }
    catch (bad_alloc ex) {
        delete[] array1;
        throw;
    }
    cout << "alloc 2" << endl;
    // Something useful with these arrays goes here!
    delete[] array1;
    cout << "deleted 1" << endl;
    delete[] array2;
    cout << "deleted 2" << endl;
    return;
}

Then, you can clean up the first (successful) allocation before re-throwing the exception for your calling function to catch!

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • @OP 'Update' - You can use std::vector as an argument for a function that expects an array: just pass "&elem[0]" for the argument, as the standard guarantees that elements are contiguous. – Adrian Mole Aug 10 '19 at 19:59
  • I think what you are trying to get at is something like the solution I have given in the edited question. – gornvix Aug 10 '19 at 20:40