簡體   English   中英

關於在默認析構函數中丟失throw說明符的c ++標准所說的內容

[英]What the c++ standard says about loosing throw specifier in default destructor

三個不同的編譯器顯示編譯此代碼的三種不同行為:

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 C ++ 5.8 Patch 121017-22 2010/09/29: 警告函數MyException ::〜MyException()只能拋出函數std :: exception :: ~exception()拋出的異常它會覆蓋

g ++ 3.4.3:`virtual MyException:~MyException()'的錯誤拋出說明符

Visual Studio 2005: 非常高興 (既不是錯誤也不是警告)

class exception {
public:
  exception () throw();
  exception (const exception&) throw();
  exception& operator= (const exception&) throw();
  virtual ~exception() throw();
  virtual const char* what() const throw();
}

我知道問題是什么以及如何解決它:

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 Studio 2005中運行了另一個小測試,我發現了一些令我驚訝的東西:

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完全忽略了異常規范。

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怎么樣?

根據C ++標准,您的程序格式不正確,因此演示了一種無法在C ++標准范圍內解釋的行為。

參考:
C ++ 03標准:

15.4例外規范[except.spec]

如果虛函數具有異常規范,則在任何派生類中覆蓋該虛函數的任何函數的所有聲明(包括定義)都應僅允許基類虛函數的異常規范所允許的異常。

[例:

 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的聲明D::f不正確,因為它允許所有異常,而B::f只允許intdouble ]

它在C ++ 11 [except.spec]中演變了一點:

5 /如果虛函數具有異常規范,則任何在任何派生類中覆蓋該虛函數的函數的所有聲明(包括定義)都只允許基類虛函數的異常規范所允許的異常。

因此,您實際上從未被允許指定更寬松的異常規范。

但是這種情況很棘手,因為析構函數實際上是由編譯器本身合成的!

在C ++ 03中,我認為標准對這些並不那么謹慎,你必須自己編寫它們,在C ++ 11中我們得到:

14 /隱式聲明的特殊成員函數(第12條)應具有異常規范。 如果f是隱式聲明的默認構造函數,復制構造函數,移動構造函數,析構函數,復制賦值運算符或移動賦值運算符,則其隱式異常規范指定type-id T當且僅當T被例外規范允許時才由f的隱式定義直接調用的f ; f應允許所有異常,如果它直接調用任何功能允許所有的異常,並f應允許也不例外,如果每次調用直接功能允許沒有例外。

編譯器將生成析構函數的異常規范,以便它匹配可以從它調用的函數拋出的內容(即屬性的析構函數)。 如果這些析構函數不拋出,那么它將生成一個滿足基類約束的noexcept析構函數。

注意:VS2005是您可能在地球上找到的最不符合標准的編譯器之一。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM