0

Let's say I have a class that looks like this:

Class A{
 private:
   int* A1;
   int* A2;
 public:
   A(): A1(new int[1000]), A2(new int[1000]){}         
   ~A(){delete[] A1; delete[] A2;}
}

I want to deal with a situation where the first allocation succeeds and the second fails, and std::bad_alloc is thrown.

From what I gather, the destructor won't be called because the object was not created successfully.

This can be dealt with if I instead do:

 A(): A1(new int[1000]), A2(new(nothrow) int[1000]){} 

Then I will be able to deal with this case without exceptions.

However, from what I read nothrow is very rarely used. I am not sure how exception can be used in this case.

Many thanks.

EL_9
  • 404
  • 2
  • 10
  • 4
    Change `A1` and `A2` to be `std::vector`, so they manage their own memory. – Igor Tandetnik Dec 14 '20 at 01:05
  • 2
    This is why in C++ it is not recommended to use bare pointers but `std::unique_ptr`. – Sprite Dec 14 '20 at 01:06
  • Does this answer your question? [Catching exceptions from a constructor's initializer list](https://stackoverflow.com/questions/160147/catching-exceptions-from-a-constructors-initializer-list) – Rane Dec 14 '20 at 01:34
  • @Rane That doesn't handle how to detect in *which* member initializer the exception was thrown. Doing that requires delegating constructors, which is a nontrivial leap of logic. – HTNW Dec 14 '20 at 01:43

1 Answers1

1

I would use std::unique_ptr.

class A {
    std::unique_ptr<int[]> A1, A2;
public:
    A() : A1(std::make_unique_for_overwrite<int[]>(1000)), A2(std::make_unique_for_overwrite<int[]>(1000)) { }
    // if A1 succeeds and A2 fails, A1 is freed
    // default no-body destructor works fine
};

But if you really want raw pointers, you can squish the logic into a chain of delegating constructors.

class A {
    int *A1, *A2;
    A(int *A1) try : A1(A1), A2(new int[1000]) { }
    catch(...) { delete[] A1; } // handle A2 fails but A1 success; automatically rethrows (note: accessing members in this catch clause is UB, but we have the constructor parameter)
public:
    A() : A(new int[1000]) { }
    // any exception in first allocation is immediately thrown here
    // any exception in second allocation bubbles up through here after being rethrown
    ~A() { delete[] A1; delete[] A2; }
};
HTNW
  • 27,182
  • 1
  • 32
  • 60