[英]C++ : noexcept (or throw()) virtual destructor = default;
[英]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
只允許int
和double
。 ]
它在C ++ 11 [except.spec]中演變了一點:
5 /如果虛函數具有異常規范,則任何在任何派生類中覆蓋該虛函數的函數的所有聲明(包括定義)都只允許基類虛函數的異常規范所允許的異常。
因此,您實際上從未被允許指定更寬松的異常規范。
但是這種情況很棘手,因為析構函數實際上是由編譯器本身合成的!
在C ++ 03中,我認為標准對這些並不那么謹慎,你必須自己編寫它們,在C ++ 11中我們得到:
14 /隱式聲明的特殊成員函數(第12條)應具有異常規范。 如果
f
是隱式聲明的默認構造函數,復制構造函數,移動構造函數,析構函數,復制賦值運算符或移動賦值運算符,則其隱式異常規范指定type-idT
當且僅當T
被例外規范允許時才由f
的隱式定義直接調用的f
;f
應允許所有異常,如果它直接調用任何功能允許所有的異常,並f
應允許也不例外,如果每次調用直接功能允許沒有例外。
編譯器將生成析構函數的異常規范,以便它匹配可以從它調用的函數拋出的內容(即屬性的析構函數)。 如果這些析構函數不拋出,那么它將生成一個滿足基類約束的noexcept
析構函數。
注意:VS2005是您可能在地球上找到的最不符合標准的編譯器之一。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.