6

在实现非抛出交换习语时,我应该使用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); }
}

特别是我担心将throw()规范放在std::swap.

奖励问题:
使用 C++0x 的noexcept关键字时答案是否不同?

4

3 回答 3

4

在 C++03 中你可以把它放在那里,但如果花哨的东西确实不会抛出,它基本上只是文档。通过向函数添加等效的环绕调用可能会或可能不会影响性能try / catch(...) { std::unexpected(); }:它是否可以在不影响性能的情况下做到这一点取决于实现。

如果您计划在 C++0x 中使用noexcept 运算符(5.3.7),那么突然之间,非抛出异常规范变得值得,以便运算符给出“正确”的答案。我真的不知道noexcept运算符的用途,但是如果它有一个聪明的通用用途,例如当某些东西不抛出时变得更有效的算法,那么我想将有必要将函数标记为非投掷,得到任何好处。

例如:

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();
    }
}

旧式异常规范(dynamic-exception-specification)在 C++0x 中已被弃用(在 C++03 中毫无意义)。

于 2010-11-13T00:25:53.067 回答
3

这不是一个好主意,不。原因是标准知道有时不可能强制执行throw()正确性,而这正是throw()最初引入的目的。特别是,在模板可能会或可能不会根据实例化抛出异常的情况下,如果没有模板实例化,就不可能检查正确性。因此,该标准甚至不需要编译器强制执行异常说明符;实际上,它禁止实现拒绝表达式“仅仅因为在执行时它会抛出或可能抛出包含函数不允许的异常”(15.4/11)。

如果throw()除了文档之外没有其他影响,则应将其注释掉;这样至少不会有误导人类观察者的风险。

情况noexcept完全不同。noexcept出于不同的原因;的表现。如果能保证编译器不会抛出异常,那么编译器允许自己执行一些优化。但是必须自己进行检查。因此,如果确实swap()不抛出(它不应该;这是它存在的理由),那么指定noexcept是一个好主意。

于 2010-11-13T00:32:59.170 回答
1

实际上,没有。异常规范是一个不错的想法,但它们的现实是它们对大多数代码的阻碍多于帮助。没有人使用它们,它们在 C++0x 中已被弃用。不要花时间在现代 C++ 中编写异常规范。

于 2010-11-13T00:29:55.673 回答