6

In my destructor, I have to clean up a few resources. Let say I have three calls to clear resources that could throw. Since it is not good for letting an exception to leave a destructor, what should be my design pattern? Apparently the way below is not scalable.

Thanks.

class B::~B(){ try{ clearResourceA() } catch{ try{ clearResourceB(); } catch{ clearResourceC(); } clearResourceC(); } clearResourceB(); . . } 
1
  • It is definitely not scalable. Trying to manage only three resources, you already have logic errors. Commented Oct 14, 2010 at 15:07

6 Answers 6

10

Why not:

try{clearResourceA();} catch(...){} try{clearResourceB();} catch(...){} try{clearResourceC();} catch(...){} 
Sign up to request clarification or add additional context in comments.

Comments

5

Encapsulate each resource in a class which clears them in its destructor (with a surrounding try/catch):

struct ProperlyManagedA { // some means of using the resource - a rudimentary way is this: A &getA() { return a; } const A &getA() const { return a; } // cleanup ~ProperlyManagedA() { try { a.clear(); // whatever it is ClearResourceA actually does } catch (...) {} } private: A a; } 

A shared_ptr with a custom deleter is one way to achieve this without having to create a whole class for each type of resource.

You might improve on discarding the exception (log the problem, for example), depending what's thrown.

Even better, modify resources A, B and C so that they clear themselves in their own destructors. That might not be possible, though.

Either way, you can then put as many such resources in a single class as you like, without adding any code to the destructor of the class. This is "scalability". The whole point of RAII, is that each user of a resource shouldn't have to write cleanup code in order to use the resource correctly.

4 Comments

Well sort-of. The purpose of RAII is that the cleanup is all done in your destructors so you don't call delete or freeHandle or whatever functions inside the bodies of your code. The main issue here is that clean-up code generally should not throw in the first place.
@CashCow: "cleanup is all done in your destructors" - well, if the resources are designed with RAII principles, then cleanup is done in the destructor of the resource. If I have to write the RAII class myself, then admittedly that is my destructor. But whoever writes the RAII resource, users of that RAII resource don't have to write or explicitly call cleanup code. That's what I meant by "users".
thanks, I was going insane while looking at the other suggestions :/
This is the only idiomatic answer. If you write C++ and don't use RAII, you're doing it wrong.
2

Capture anything that can throw in your destructor with a catch-all (i.e., catch (...)) and do your best to handle the exceptions thrown. Make sure that no exceptions propagate out of the destructor, which the catch-all will help you prevent.

Comments

2

You could also wrap your ClearResources functions to ensure they never throw. Why might they throw anyway?

1 Comment

Some kind of flush (or other I/O) is the usual reason.
1

Because you asked about design pattern I'll tell what rule of thumb I use with success. All function which have clean-up/termination functionality should NEVER throw.

Those functions are usually well recognized names:

  • Clear*()
  • Clean*()
  • Terminate*()
  • Destroy*()
  • Release*()
  • Detach*()
  • Free*()
  • Erase*()
  • ~Destructor()
  • ...

The rationale which stands behind this is that:

  • there must by at least 1 function per resource which guarantees that specific resource is cleared
  • (recursively) if you build clean-up function and you release multiple resources then use only functions which guarantee that these resources will be released in exception safe way
  • programmers which uses your code must have way to clean-up resource
  • if you export clean-up functions outside library then don't propagate exception (because users of library won't know if resource is released)

And I it is possible try to use RAII pattern. But even in this case above rules will be in use.

Comments

0
try { ClearResourceA(); } catch(...) { ExceptionWasThrown(); } try { ClearResourceB(); } catch(...) { ExceptionWasThrown(); } ... 

4 Comments

Offtop: How can I enforce indentation?
Use the "code" button, not the back ticks. The code button has a 101010 on it. Type in your code (indented), highlight the code, then push the code button.
@Starkey: Unfortunately today there are neither those buttons nor the preview. I asked on meta but still pending answer
four initial spaces implies "code", there's no need for backticks as well.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.