0

Please consider the following C++20 program:

struct S1 {
   ~S1() { std::cout << "~S1" << std::endl; }  
};

struct S2 {
    S1 s1;

    S2() {
        throw std::runtime_error("error");
    }

    ~S2() {
        std::cout << "~S2" << std::endl;
    }
};

int main() {
    try {
        S2* s2 = new S2;
    } catch (...) {
    }
}

The output of this program is:

~S1

I think because the constructor of S2 didn't complete, the body of its desctructor isn't run, but the destructors of subobjects that did complete construction are run.

What I'm not sure about is the new expression. Clearly it must allocate memory for the object before it starts executing the constructor. Given that the constructor exited with an exception, is this allocated memory automatically freed as well?

The question is: does the above program leak memory? (As in, absolutely guaranteed by the standard? No undefined/unspecified behaviour?)

Andrew Tomazos
  • 58,923
  • 32
  • 156
  • 267
  • The answers at the linked question don't go far into nerdy details, but this is what "placement delete" is for. – Potatoswatter Mar 01 '21 at 16:42
  • That means you may leak memory though https://gcc.godbolt.org/z/aKobPd – Ayxan Haqverdili Mar 01 '21 at 16:46
  • @AyxanHaqverdili, that demonstrates a bug in the example. The array should be allocated by `unique_ptr`. – Potatoswatter Mar 01 '21 at 17:00
  • @Potatoswatter that does not cover every single design though. In the general case, it is possible (and common) that you want to do something in the constructor which you clean up in the destructor (that's the point of a destructor). Unless you're super careful, this may leak resources, even those that are not memory related. Otherwise why even even have a destructor? – Ayxan Haqverdili Mar 01 '21 at 17:02
  • 1
    @AyxanHaqverdili If you have a design where you must use raw pointers that are not immediately wrapped in smart pointers, you must indeed be super careful. The answer to OP's question implies that if you *do* immediately wrap raw pointers in smart pointers, then such caution is not needed. They are two different scenarios. – Brian Bi Mar 01 '21 at 17:07
  • @BrianBi I completely agree with you. I was just not aware that the destructor is not run in this case. I don't know what I was expecting, since running the destructor on a not-completely-constructed class could potentially be disastrous. I guess I subconsciously consider destructors as that rock-solid, deterministic, guaranteed to run unless you do something horrible part of the language, so I never entertained the idea of them being ignored. – Ayxan Haqverdili Mar 01 '21 at 17:16

0 Answers0