3

I came across this fringe question that I would normally dismiss with "don't do that", but I couldn't find a satisfactory answer in the standard and would appreciate if someone could point out the reasoning:

Suppose a I have a class that throws an exception in the destructor:

struct Foo { ~Foo() { throw std::runtime_error("Catch this!"); } };

What happens to the dynamically allocated memory if I delete a dynamically allocated instance of this class?

auto p = new Foo;

try { delete p; }
catch (std::exception const &) { }

Is the deallocation function called or not? And why? Could I make this code correct by adding operator delete(p); into the catch block?

I ran a small test with GCC which seems to not deallocate the memory automatically. (Contrast this with exceptions in the constructor, in which case the deallocation function is guaranteed to be called (if it exists).)

ChrisW
  • 54,973
  • 13
  • 116
  • 224
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • No, you cannot make it correct by adding `operator delete(p)`, unless you used `operator new()` and placement new to construct the object, and then you'd need to call the destructor explicitly also. In general, you need to keep pointers to raw allocated buffers and pointers to objects separate. (For arrays, they may not even have the same address.) – Ben Voigt Dec 09 '12 at 23:29
  • @BenVoigt: Can you back this up somehow? I just noticed that adding `operator delete(p)` does seem to make my program valgrind-clean, but is that actually UB? Isn't a `new` expression guaranteed to call `operator new`? – Kerrek SB Dec 09 '12 at 23:32
  • The Standard says "The address of the created object will not necessarily be the same as that of the block if the object is an array." Moreover, the rules concerning calling a deallocation function require you to have gotten the pointer from the matching allocation function. – Ben Voigt Dec 09 '12 at 23:36
  • [Don't do that](http://yosefk.com/c++fqa/exceptions.html#fqa-17.3) – ChrisW Dec 09 '12 at 23:37
  • @BenVoigt: Yeah, I know that arrays are problematic. But I thought for non-array objects there was no room for any misbehaviour... – Kerrek SB Dec 09 '12 at 23:37
  • @Kerrek: It probably works on most compilers. But I consider it bending the rules. Of course, [some of the rules may need to be fixed](http://stackoverflow.com/q/4418220/103167). – Ben Voigt Dec 09 '12 at 23:40
  • For one thing, it can be pretty difficult to invoke the correct deallocation function in any sort of portable generic way. – Ben Voigt Dec 09 '12 at 23:41
  • 1
    @ChrisW: The question already said that. It's still interesting to find out what the rules are when you go against all sane advice. – Ben Voigt Dec 09 '12 at 23:42
  • I filed a [bug report for GCC](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55635). – Kerrek SB Dec 09 '12 at 23:56
  • @BenVoigt: Yeah, the placement-array-new is definitely broken to the point of being unusable. I think someone on the DR mailing list said that there simply hasn't been anyone to write this up as a paper that's needed for a proper DR. – Kerrek SB Dec 09 '12 at 23:57

1 Answers1

6

The Standard says (5.3.5p7):

If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will call a deallocation function. Otherwise, it is unspecified whether the deallocation function will be called. [ Note: The deallocation function is called regardless of whether the destructor for the object or some element of the array throws an exception. — end note ]

The note answers your question.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720