Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

confusion about non-throw functions

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?

like image 474
Alcott Avatar asked Aug 07 '12 08:08

Alcott


People also ask

What happens when Noexcept function throws?

If you throw, your program terminates What happens if you throw from a noexcept function? Your program terminates, and may or may not unwind the stack. Terminating program isn't the nicest way to report an error to your user. You would be surprised that most of C++ code might throw.

Why noexcept?

There are two good reasons for the use of noexcept: First, an exception specifier documents the behaviour of the function. If a function is specified as noexcept, it can be safely used in a non-throwing function. Second, it is an optimisation opportunity for the compiler.

What does noexcept mean?

The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.

What is an exception specification explain using suitable example?

Exception specifications are a C++ language feature that indicate the programmer's intent about the exception types that can be propagated by a function. You can specify that a function may or may not exit by an exception by using an exception specification.


2 Answers

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.

like image 200
Gorpik Avatar answered Sep 23 '22 20:09

Gorpik


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.

like image 26
juanchopanza Avatar answered Sep 21 '22 20:09

juanchopanza