【问题标题】:Overrriding destructor of std:exception重写 std:exception 的析构函数
【发布时间】:2013-08-27 07:53:06
【问题描述】:

如果注释了line 8,则以下程序无法在 g++ 4.4 中编译。为什么?似乎当我重写 std::exception 构造函数时,我也必须重写它的析构函数。这是什么原因?

#include<iostream>
#include<exception>
using namespace std;

class A : public exception {
public:
    A(string msg) : _msg(msg) {}
    //~A() throw(){};                     // line 8
    const char* what() const throw() { return _msg.c_str();}    
private:
    string _msg;
};

int main()
{
}

编译错误是:

error: looser throw specifier for ‘virtual A::~A()’

【问题讨论】:

  • 编译器是否报错?如果是这样,为什么不在问题中?
  • @DavidHeffernan,thanx,已修复
  • 这是他的问题在底部(虽然可能是在编辑之后)。当然与 4.8.1 相同,因为默认的析构函数不会有此处请求的 throw 说明符。
  • @Laszlo 是的,它是在编辑并添加错误后的问题中

标签: c++ exception exception-handling destructor throw


【解决方案1】:

这是因为析构函数需要一个 throw() 说明符。如果你没有在你的类中指定它,编译器会为你的类编写它自己的默认析构函数,并且默认析构函数不会指定你不抛出异常。

这是正确的,因为 std::exception 的公共析构函数还指定了throw()

~A() throw(){};

来自标准 (N3225) 12.4.4:

如果一个类没有用户声明的析构函数,则析构函数被隐式声明为 >defaulted (8.4)。一个隐含的—— 声明的析构函数是其类的内联公共成员。

因此,如果您自己不声明析构函数,编译器会创建下一个析构函数。如果nothrow 符合条件的所有异常成员析构函数,编译器可能会生成指定throw() 的析构函数。

~A(){};

从技术上讲,可以从这个析构函数中抛出异常,但这将是一种非常糟糕的编程风格,因此从std::exception 派生的异常保证您不会在std::exception 派生类的析构函数中引发任何异常.

编辑 如果 std::string 的析构函数是 noexcept 指定,则较新的编译器将提供一个具有 noexcept 说明符的析构函数。如果所有成员的析构函数都没有抛出异常(noexcept 限定),其他编译器也会生成一个noexcept 析构函数。 这是 C++11 标准在第 15.4 章中规定的。 [除了.spec]

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

【讨论】:

  • 这并不是全部。如果编译器生成的析构函数直接调用的所有函数都不允许异常(非静态数据成员的析构函数和基类的析构函数),则编译器生成的析构函数将具有nothrow 规范。该示例无法编译,因为std::string 成员的析构函数未标记为throw()。尝试用const char* 替换它,看看有什么不同。
  • gcc 4.8.1clang 3.4 都可以很好地编译 OP 的代码。也就是说,在 C++11 中。不知道C++03以后有没有改过。
  • 如果您不介意,我添加了标准中的规范性引用。和 +1。
  • 您不应将“nothrow”作为关键字突出显示。有一个 std::nothrow 类型的默认对象 std::nothrow_t 用于“非抛出 new”,但“非抛出异常规范”要么是 throw() [在 C++98/03 中,在C++11] 或 [在 C++11 中] noexcept(或 noexcept(true),或任何 noexcept( CE ) 其中常量表达式 CE 计算结果为true(包括有趣的noexcept( noexcept( 表达式 ) ),其中表达式 可以在编译时证明不抛出)。
  • @gx_ 我在 noexcept 中更改了 nothrow
猜你喜欢
  • 2013-06-10
  • 2011-01-16
  • 2017-10-11
  • 2012-03-06
  • 1970-01-01
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 2015-08-01
相关资源
最近更新 更多