以下代码不在gcc-4.7.1下编译,而是在clang-3.2下编译。哪一个遵循C ++ 11标准?
struct X {
virtual ~X() = default;
};
struct Y : X {
virtual ~Y() = default;
};
gcc-4.7.1抱怨说:
looser throw specifier for 'virtual Y::~Y()'
error: overriding 'virtual X::~X() noexcept(true)'
显然,gcc-4.7.1认为X的默认析构函数是nothrow,但是Y的默认析构函数并不是没有。为什么是这样?任何人都可以参考标准中的正确位置吗?感谢。
我在stackoverflow上看到了类似的问题,但我没有看到答案参考标准。
答案 0 :(得分:37)
由于以下原因,编译器陷入两难境地:
(1)在函数声明中未指定任何异常(即不使用throw
或noexcept
(相当于noexcept(true)
))表示允许该函数抛出所有可能的异常:
(§15.4/ 12,强调我的)具有无异常特定的函数或具有
noexcept(constant-expression)
形式的异常特征的函数,其中constant-expression
产生{{ 1}} 允许所有例外。 [...]
(2)默认析构函数必须准确允许由其隐式定义直接调用的函数允许的异常:
(§15.4/ 14,强调我的)隐含声明的特殊成员函数(第12条)应具有异常规范。 如果f是隐式声明的默认构造函数,复制构造函数,移动构造函数,析构函数,复制赋值运算符或移动赋值运算符,其隐式异常规范指定type-id T当且仅当T由f的隐式定义直接调用的函数的异常指定允许时;如果它直接调用的任何函数允许所有异常,则f应允许所有异常,如果它直接调用的每个函数都不允许异常,则f不允许异常。
(3)当特殊成员(例如析构函数)显式默认时,即当您使用false
时,异常规范可选(看下面使用“可能”:
(8.4.2 / 2,强调我的)明确默认的功能 [...] 只有在兼容时才有明确的异常规范( 15.4)隐含声明的例外规范。 [...]
标准中没有声明要求明确默认的析构函数中的异常规范。
结论:因此,未指定显式默认析构函数的异常可以通过两种方式解释:
不幸的是,GCC在你的基类声明的情况下以一种方式解决了这种困境(支持“无例外”),并且在派生类的情况下以不同的方式解决(支持“所有例外”)有)。
我认为对这种公认的模糊情况的最自然的解释是假设(2)和(3)覆盖(1)。标准没有这样说,但它应该。根据这种解释,Clang似乎就在这里。