我们应该提供一个没有抛出说明符的析构函数吗?

时间:2012-05-25 14:37:00

标签: c++ exception destructor throw specifier

namespace QuantLib {

    //! Base error class
    class Error : public std::exception {
      public:
        /*! The explicit use of this constructor is not advised.
            Use the QL_FAIL macro instead.
        */
        Error(const std::string& file,
              long line,
              const std::string& functionName,
              const std::string& message = "");
        /*! the automatically generated destructor would
            not have the throw specifier.
        */
        ~Error() throw() {}
        //! returns the error message.
        const char* what() const throw ();
      private:
        boost::shared_ptr<std::string> message_;
    };

}

通过注释看,类Error的析构函数显式提供了一个带有无抛出说明符的空实现。

问题:这有必要吗?或者这是一个很好的做法,比较让编译器生成隐式析构函数?

4 个答案:

答案 0 :(得分:9)

在C ++ 11中,析构函数是隐式throw()(除非该类型的任何成员或基类具有带有不同异常规范的析构函数),因此如果您在C ++ 11模式下进行编译,则不需要。

如果你在C ++ 03中,你可能想要添加它,但是它是否会产生效果是非常实现的定义......现在,为了文档目的,你可能想要添加它,但是,通常认为析构函数不会抛出。

答案 1 :(得分:5)

Destructors should always be designed to never throw exceptions。因此,从这个意义上说,仅仅为了将其标记为无抛出而声明空的析构函数几乎没有意义。

答案 2 :(得分:4)

取决于您的想法throw()的含义。

根据标准实际意味着“在必要时或在函数本身中对每个函数调用添加额外代码,以确保如果此函数抛出则异常被捕获并且std::unexpected被称为“。

某些编译器将其实现为“在假设它们不会抛出的情况下优化对此函数的调用”,但(违反标准)未实现运行时检查。

因此,将它添加到析构函数(当然不应该抛出)(但实际上可能不会)添加一个永远不会被触发的运行时检查,因此可能有助于调试代码。它可能会也可能不会启用优化。

答案 3 :(得分:3)

析构函数总是隐式具有异常规范:

[class.dtor] 12.4 p3

  

没有异常规范的析构函数声明被隐式地认为具有与隐式声明相同的异常规范(15.4)。

[except.spec] 15.4 p14

  

隐式声明的特殊成员函数(第12条)应具有异常规范。如果f是隐式声明的默认构造函数,复制构造函数,移动构造函数,析构函数,复制赋值运算符或移动赋值运算符,则其隐式异常规范指定type-id T当且仅当T被例外规范允许时才由f的隐式定义直接调用的函数;如果它直接调用的任何函数允许所有异常,则f应允许所有异常,如果它直接调用的每个函数都不允许异常,则f不允许异常。

所以,不,你没必要使用异常规范。


在C ++ 03中,用户定义的析构函数没有隐式异常规范,因此如果您确实定义了自己的析构函数,则不能依赖编译器自动添加相应的异常规范。但隐式声明的析构函数具有与C ++ 11中相同的隐式异常规范。