9

假设我有:

class Foo
{
public:
   virtual ~Foo()=default;
};

默认析构函数的异常规范是什么?默认析构函数是否等效于:

   virtual ~Foo() {};
or
   virtual ~Foo() throw() {};
or
   virtual ~Foo() noexcept {};

C++11 标准的 15.4 节说它取决于析构函数的隐式定义直接调用的函数的异常规范。在这种情况下,没有成员,也没有基类,因此 AFAIK 没有由隐式析构函数直接调用的函数。这是标准中的歧义(或遗漏)吗?

当然,这很重要,因为如果它隐式具有 throw(),那么所有子类都必须使用 throw() 声明它们的析构函数。不要告诉我在析构函数中抛出异常是个坏主意,我知道。我处理了许多根本没有使用异常规范的遗留代码。

作为一个信息点,当我尝试时:

class SubFoo : public Foo
{
public:
   virtual ~SubFoo();
};

我在 GCC 4.4 中遇到了一个错误(不匹配的异常规范)(尽管我承认我可能没有正确的命令行开关),但在使用“11”编译器的 XCode 4.3 中却没有。

4

2 回答 2

4

回到同一句话的前面(§15.4/14):

...它的隐式异常规范指定类型 ID T 当且仅当 T 被 f 的隐式定义直接调用的函数的异常规范允许时;..."

因此,如果~Foo不调用任何函数,则它有一个不允许抛出异常的隐式声明。

根据§15.4/3:

如果满足以下条件,则两个异常规范是兼容的:

  • 两者都是非投掷(见下文),无论其形式如何,

throw()这里就是这种情况,所以声明是或noexcept- 两者在任何情况下都兼容并不重要。

于 2012-05-24T04:49:39.413 回答
2

标准语言在C++11 §8.4.2/2中很好地开始,

如果一个函数在它的第一个声明中被显式默认,
——如果隐式声明是,它被隐式认为是 constexpr,
——它被隐式认为具有相同的异常规范,就好像它已经被隐式声明(15.4),......

但是,在C++11 §15.4/14中,逻辑迅速转移,

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

在标准的“允许”含义中,它是关于通过异常规范明确允许的。

如果f调用两个函数,其中一个指定并因此允许T,另一个允许所有异常,则f必须同时指定T 允许所有异常,这是不可能的。

所以这绝对看起来像是标准中的一个缺陷。

我找到了相关的缺陷报告,http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1351

然而,看起来这个区域只是一个大混乱。:-(

于 2012-05-24T05:01:35.757 回答