首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >c++标准关于在缺省析构函数中丢失抛出说明符的规定

c++标准关于在缺省析构函数中丢失抛出说明符的规定
EN

Stack Overflow用户
提问于 2012-03-09 22:14:46
回答 2查看 8.2K关注 0票数 19

三个不同的编译器显示了编译此代码的三种不同行为:

代码语言:javascript
复制
class MyException : public std::exception
{
 public:
  MyException(std::string str) : m_str(str) {}
  virtual const char * what() const throw () {return m_str.c_str(); }
 protected:
  std::string m_str;
};

Sun exception 5.8修补程序121017-22 2010/09/29:警告函数MyException::~MyException()只能抛出它所覆盖的std::exception::~exception()函数引发的异常

g++ 3.4.3:Error ` `virtual::~MyException()‘的松散抛出说明符

Visual Studio2005:It is very happy (没有错误或警告)

代码语言:javascript
复制
class exception {
public:
  exception () throw();
  exception (const exception&) throw();
  exception& operator= (const exception&) throw();
  virtual ~exception() throw();
  virtual const char* what() const throw();
}

我知道问题是什么,以及我如何解决它:

代码语言:javascript
复制
class MyException : public std::exception
{
 public:
  MyException(std::string str) : m_str(str) {}
  virtual const char * what() const throw () {return m_str.c_str(); }
  ~MyException() throw() {}  <------------ now it is fine!
 protected:
  std::string m_str;
};

然而,我想知道在特定情况下标准是怎么说的。

我在Visual Studio2005中运行了另一个小测试,我发现了一些让我非常惊讶的东西:

代码语言:javascript
复制
struct Base
{
    virtual int foo() const throw() { return 5; }
};

struct Derived : public Base
{
    int foo() const { return 6; }
};

int main()
{
    Base* b = new Derived;
    std::cout << b->foo() << std::endl; //<-- this line print 6!!!
    delete b;
}

这两个函数的签名不同。这是如何工作的呢?似乎visual studio 2005完全忽略了异常规范。

代码语言:javascript
复制
struct Base
{
    virtual int foo() const throw() { return 5; }
};

struct Derived : public Base
{
    int foo() { return 6; } // I have removed the const keyword 
                            // and the signature has changed
};

int main()
{
    Base* b = new Derived;
    std::cout << b->foo() << std::endl; // <-- this line print 5
    delete b;
}

这是c++标准吗?有什么神奇的标志可以设置吗?

VS2008和VS2010呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-03-09 22:23:49

根据C++标准,您的程序是病态的,因此演示了一种在C++标准范围内无法解释的行为。

参考资料:

C++03标准:

15.4 Exception specifications except.spec

如果虚函数有异常规范,则在任何派生类中重写该虚函数的任何函数的所有声明都应仅允许基类虚函数的异常规范所允许的异常。

[示例:

代码语言:javascript
复制
 struct B 
 {
    virtual void f() throw (int, double);
    virtual void g();
 };
 struct D: B 
 {
    void f(); // ill-formed
    void g() throw (int); // OK
 };

D::f的声明格式错误,因为它允许所有异常,而B::f只允许intdouble。]

票数 6
EN

Stack Overflow用户

发布于 2012-03-09 22:32:26

它在C++11 except.spec中稍有发展

5/如果虚函数有异常规范,则在任何派生类中覆盖该虚函数的任何函数的所有声明(包括定义)都应仅允许基类虚函数的异常规范所允许的异常。

因此,实际上永远不允许您指定更宽松的异常规范。

然而,这种情况很棘手,因为析构函数实际上是由编译器本身合成的!

在C++03中,我认为标准在这些方面并不是很小心,你必须自己编写它们,无论我们得到什么,在C++11中:

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

编译器将生成析构函数的异常规范,以便与它调用的函数(即属性的析构函数)可以抛出的内容相匹配。如果这些析构函数没有抛出,那么它将生成一个满足基类约束的noexcept析构函数。

注意: VS2005是你可能在地球上找到的最不符合标准的编译器之一。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9635464

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档