8
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

4 回答 4

9

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

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

于 2012-05-25T14:44:21.343 回答
5

析构函数应始终设计为从不抛出异常。所以从这个意义上说,声明一个空的析构函数只是为了将其标记为不抛出是没有意义的。

于 2012-05-25T14:44:28.590 回答
4

看你觉得是什么throw()意思。

根据标准,它的实际含义是,“如有必要,在每次调用此函数或在函数本身中添加额外的代码,以确保如果此函数抛出,则异常被捕获并被std::unexpected调用”。

某些编译器实现它的意思是“在假设它们不会抛出的情况下优化对这个函数的调用”,但是(违反标准)没有实现运行时检查。

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

于 2012-05-25T14:46:31.573 回答
3

析构函数总是隐含着异常规范:

[class.dtor] 12.4 p3

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

[除了.spec] 15.4 p14

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

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


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

于 2012-05-25T14:48:11.150 回答