开发者

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

开发者 https://www.devze.com 2023-01-25 02:00 出处:网络
When implementing the non-throwing swap idiom, should I use throw()? namespace A { struct B { void swap( B& other ) throw()

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?


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).


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.


Realistically, no. Exception specifications were a lovely idea, but the reality of them was that they hindered more than helped the majority of code. Nobody uses them and they're deprecated in C++0x. Don't spend time writing exception specifications in modern C++.

0

精彩评论

暂无评论...
验证码 换一张
取 消