I was recently tasked with hunting down a memory leak in a part of our code. The leak ended up being in the destructor for a particular object…and I found something really strange. A former coworker wrote this:
File::~File()
try
{
Clear();
}
catch (...)
{
Log("caught exception");
}
The file class inherits from some base classes. My first question is: is this strictly legal C++? It compiles in Visual Studio 2008, but I showed it to a few friends / coworkers and they were fairly horrified that it worked.
It doesn’t actually work as intended, though: the base class that this object inherits from has a destructor that is now never called (as opposed to if you just wrapped the destructor in a regular method block, having the try / catch as part of that method).
Can anyone take a stab at explaining why this is allowed, and why the base class destructor was not called? The destructor here was not throwing.
This is a function try block and it’s completely legal.
See, for example, here.
The only time that you can do something in a function try block that you can’t do in a normal try block in a function is catch exceptions thrown by expression in a constructor initializer list (and even then you end up having to throw something), but that doesn’t apply here.
This GOTW #66 is particularly interesting, although it concentrates more on constructors. It contains this “moral”:
Just to add clarification, the code as written will cause any exception caught to be rethrown due to ISO/IEC 14882:2003 15.3 [except.handle] / 16:
However it is legal to have a parameterless
returnin the handler of a function try block for a destructor – it is only forbidden in a function try block for a constructor – and this will supress the rethrow of the exception. So either of these alternatives would prevent the exception from leaving the destructor.