Pregunta

I have 2 questions about non-throwing functions:

  1. Why make a function non-throwing?

  2. How to make a function non-throwing? If the code inside the function actually may throw, then should I still make it non-throwing?

Here is an example:

void swap(Type t1, Type t2) throw()
{
    //swap
}

If the code in swap won't throw at all, should I still append throw()? Why?

¿Fue útil?

Solución

throw() (or noexcept in C++11) is useful for two reasons:

  1. It allows the compiler to be more aggressive in its optimisations.
  2. It tells function users that they can use this function in their own non-throwing functions.

Non-throwing functions are very important for writing exception safe code. For instance, the usual way of writing an exception safe operator= is via a non-throwing swap() function.

On the other hand, other exception specifications are useless and have been justly deprecated in the current standard. They don't mix well at all with templates and are too expensive to enforce.

Now, if you use a noexcept specification in a function that might actually throw, all bets are off. Even if your compiler does not terminate the program when an exception leaves the function (VS does not do it for runtime efficiency reasons, for instance), your code might not do what you thought because of optimisations. For example:

void f() noexcept
{
  a();
  b();
}

If a() actually throws and b() has side effects, the function behaviour will be unpredictable, because your compiler may decide to execute b() before a(), since you have told it that no exceptions will be thrown.

EDIT: Now for the second part of your question: how to make a function non-throwing?

First you need to ask yourself whether your function should really be non-throwing. For instance:

class C
{
  C* CreateInstance()
  {
    return new C();
  }
}

Since operator new can throw a std::bad_alloc, CreateInstance() can throw. You could try to avoid it with a try-catch block, handling or swallowing any exceptions that may be thrown inside the try block, but would that really be sensible? For instance:

C* CreateInstance()
{
  try
  {
     return new C();
  }
  catch (...)
  {
     return null;
  }
}

Problem solved, it seems, but would your callers be prepared for CreateInstance() returning null? If not, a crash will ensue when they try to use that pointer. Besides, a std::bad_alloc usually means that you have run out of memory and you would just be postponing the problem.

So be careful: some functions can be made non-throwing, but others should be allowed to throw. Exception safety is not a trivial matter.

Otros consejos

Why make a function non-throwing?

So callers of the function can call it without having to take any actions to deal with exceptions being raised by the function.

How to make a function non-throwing? If the code inside the function actually may throw, then should I still make it non-throwing?

You can make the code non-throwing by putting all code which could throw the inside a try block, and deal with any exceptions without re-throwing.

void swap(T t1, T t2) noexcept {
  try {
    // ....
  } catch (const std::exception& ex) {
    // ....
  } catch (...) {
    // ....
  }

}

If you claim your function doesn't throw, then you have to make it non-throwing. But this doesn't mean adding an exception specification, which you shouldn't do anyway, since it is deprecated. It means you must ensure the function doesn't throw, no matter what. The C++11 keyword noexcept gives you some compile-time safety in this respect.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top