Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use throw() when implementing non-throwing swap?

Tags:

c++

noexcept

swap

When implementing the non-throwing swap idiom, should I use throw()?

namespace A
{
   struct B
   {
     void swap( B& other ) throw()
     { /* fancy stuff that doesn't throw */ }
   };

   void swap( B& lhs, B& rhs ) throw()
   { lhs.swap(rhs); }
}

namespace std
{
   template<>
   void swap( A::B& lhs, A::B& rhs ) throw()
   { lhs.swap(rhs); }
}

In particular I worry about putting the throw() specification on the specialization of std::swap.

Bonus question:
Is the answer different when using C++0x's noexcept keyword?

like image 797
deft_code Avatar asked Nov 13 '10 00:11

deft_code


2 Answers

In C++03 you can put it there, but if it's true that the fancy stuff doesn't throw, it's basically just documentation. It may or may not affect performance by adding the equivalent of try / catch(...) { std::unexpected(); } around calls to the function: it's up to the implementation whether it can do it without affecting performance.

If you're planning to use the noexcept operator (5.3.7) in C++0x, then suddenly it becomes worth having non-throwing exception specifications, so that the operator gives the "right" answer. I don't really know what the noexcept operator is for, but if there's a clever generic use for it, for example algorithms that become more efficient when something is non-throwing, then I guess it's going to become necessary to mark functions as non-throwing, to get whatever the benefit is.

For example:

void foo() noexcept;
void bar();

template <void(*FUNC)()>
void generic_thing() {
    if (noexcept(FUNC()) {
        // this won't throw, perhaps we can somehow take advantage of that
        FUNC();
    } else {
        // this might throw
        FUNC();
    }
}

Old style exception specifications (dynamic-exception-specification) are deprecated in C++0x (and pointless in C++03).

like image 146
Steve Jessop Avatar answered Sep 19 '22 01:09

Steve Jessop


It's not a good idea, no. The reason is that the standard knows that at times it's impossible to enforce the throw() correctness, which is what throw() was brought in for in the first place. In particular, in the case of templates where an exception may or may not be thrown depending on the instantiation it's impossible to check for correctness without the template instantiation. The standard therefore doesn't even require compilers to enforce the exception specifier; in fact, it forbids an implementation from rejecting an expression "merely because when executed it throws or might throw an exception that the containing function does not allow" (15.4/11).

If throw() has no effect other than documentation then it should be commented out; this way at least it doesn't pose a risk of misleading the human observer.

The case with noexcept is wholly different. noexcept comes to be for a different reason; that of performance. If you can guarantee the compiler no exception is thrown then the compiler allows itself to perform some optimizations. But you will have to do the checks yourself. So, if indeed swap() doesn't throw (and it shouldn't; that's its raison d'être) then specifying noexcept is a good idea.

like image 28
wilhelmtell Avatar answered Sep 20 '22 01:09

wilhelmtell