我应该在实现非投掷交换时使用throw()吗?

时间:2010-11-13 00:12:06

标签: c++ swap noexcept

在实现非投掷交换习语时,我应该使用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关键字时,答案是否有所不同?

3 个答案:

答案 0 :(得分: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();
    }
}

旧式异常规范(动态异常规范)在C ++ 0x中已弃用(在C ++ 03中无意义)。

答案 1 :(得分:3)

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

如果throw()除了文档之外没有任何影响,那么它应该被注释掉;这样至少它不会造成误导人类观察者的风险。

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

答案 2 :(得分:1)

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