3

I have a engine.dll module which implements several processing functions, and I created a PublicInterface.h, defining functions for external access,

namespace PublicInterface {
  void do_a();
  void do_b();
}

I would like to guarantee that every call to functions in PublicInterface are protected with a try catch block. In other words, I want engine.dll to handle all the exceptions it throws. What would be the best way of implementing this?

I thought of creating an additional function,

void protectedRun(std::function<void()> f) {

try {
    f();
}
catch (...) {
    _handle();
}

But how can I enforce that all the functions from PublicInterface.h will be called from protectedRun()?

Or is there a better way of implementing this?

manatttta
  • 3,054
  • 4
  • 34
  • 72
  • 5
    Why do you think you want to do this? – BoBTFish Feb 27 '15 at 10:55
  • 1
    Plus one, well-posed question but a terrible idea. – Bathsheba Feb 27 '15 at 10:57
  • @BoBTFish So that it would not be necessary to create a try catch block to every `PublicInterface` function call – manatttta Feb 27 '15 at 10:57
  • Only the caller knows how to handle the error, so you can't provide the wrapper. If you *are* the caller, then sure, provide your own wrapper for convenience, but don't force everyone else to use it. (And of course, clearly document that the function can throw, what it can throw, and when.) – BoBTFish Feb 27 '15 at 10:59
  • @Bathsheba maybe, but the exception handler is the same for all the modules (both internal and external to `engine.dll`), so it could be encapsulated inside `PublicInterface` implementation instead of calling the handler in the external modules – manatttta Feb 27 '15 at 11:00
  • http://stackoverflow.com/questions/1055387/throw-keyword-in-functions-signature – thang Feb 27 '15 at 11:01
  • Is your question equivalent to saying that you want to provide "No-throw guarantee" for your interface? – sanjayk79 Feb 27 '15 at 11:03
  • @sanjayk79 what I want is to ensure that `engine.dll` will handle its own exceptions – manatttta Feb 27 '15 at 11:04
  • 1
    @manatttta: So say that `do_a` fails due to an out-of-memory condition = `std::bad_alloc`. How does the caller of `do_a` know that the call failed, if you hide the exception? – MSalters Feb 27 '15 at 11:13
  • @MSalters it displays a log msg to the user. the interface does not need to be aware of this, as it only serves for trigerring processing functions – manatttta Feb 27 '15 at 11:18
  • @manatttta: I don't think the library can decide on behalf of the caller that the caller need not know that `do_a` failed. Perhaps a better name would be `void try_a_but_ignore_failure( )` – MSalters Feb 27 '15 at 11:22

3 Answers3

1

The solution depends on what you want to achieve:

If you want the user to handle all possible exceptions from your code, then there is no direct way to force them to call the functions using protectedRun. C++ doesn't have the equivalent of Java's checked exceptions.

If you want to make sure that no exceptions from your code propagate to the caller's code, you could for example add a new public interface that handles all exceptions and (optionally) make your current public interface private.

In short, either the user will have access to the exceptions from your code (possibly not handling them), or he won't (and not have any option of handling them).

anderas
  • 5,744
  • 30
  • 49
1

Implement it as follows:

using exceptionHandler = void(*)(std::exception& e);
void defaultHandler(std::exception& e) { throw e; }

namespace PublicInterface {
  void do_a(exceptionHandler eh = &defaultHandler);
  void do_b(exceptionHandler eh = &defaultHandler);
}

Inside your functions, don't throw directly but pass the exception to (*eh)().

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

The only real way is to not put functions throwing exceptions into the public interface. Instead, place your protectedRun() function in the public interface, and have it call your throwing functions, catch those exceptions, and (most importantly) correct the problem that resulted in an exception being thrown.

Fundamentally, however, the fact you have functions throwing exceptions and are trying to force the manner in which they are caught shows that your library has a severe design flaw.

The whole point of exceptions is a mechanism to report an error condition that (a) cannot be corrected where the condition is detected and (b) the condition must be corrected before anything else (other than program termination) can occur.

Trying to dictate that the caller must immediately catch the exception and correct the cause is pointless. If the caller cannot correct the cause, but was somehow forced to catch it anyway, the only option available would be to rethrow the exception. Apart from additional runtime overhead of catching and rethrowing, that has the same effect (stack unwinding) as if the caller does not catch the exception at all.

What you need to do is think carefully about WHETHER OR NOT it is appropriate for functions in your library to throw exceptions at all. Because it is not the responsibility of the caller of your library functions to catch exceptions. It is the responsibility of your library functions to throw exceptions in a manner that makes sense to the caller.

There is also a basic concern that, depending on your toolchains (compiler, linker, etc used to build the DLL versus those used to build the calling program) and environment (host system, etc) exceptions may not cleanly cross a DLL boundary anyway.

Rob
  • 1,966
  • 9
  • 13