2017-03-16 56 views
4

有沒有可能導致C++異常的「代碼語句」的完整列表(可能是遞歸定義的)?事情是這樣的:什麼(和什麼不能)在C++中拋出異常?

1)throw聲明(自然)

2)調用new

3)調用從標準庫被記錄在案,以便能夠拋出任何功能。

4)調用任何包含1-3操作的用戶定義函數(包括構造函數)。

5)別的嗎?在堆棧上分配本地對象,對內置類型進行操作,取消引用指針,類型轉換 - 是否可以拋出?

6)其他一切都是免費的。

通過免例外我並不是指總是成功的操作。解引用指針肯定不是。但是,將它包裝在try-catch塊中仍然沒有意義,請考慮函數解引用指針的異常安全性等。因此,成功或導致未定義行爲的代碼可以被視爲無異常。

Upd。儘管我最後一段我仍然有一個評論,未定義的行爲也可以拋出,所以讓我解釋我的意思。請考慮下面的代碼:

void bar(); 
Class C{ 
... 
public: 
    foo() { 
    something_that_breaks_class_invariants; 
    bar(); 
    something_that_restores_class_invariants; 
    } 
} 

如果我正確理解什麼異常安全之約,然後如果bar()可以拋出異常,該代碼是壞的。我應該改變語句的順序,否則我應該把bar()換成try-catch塊,恢復類不變量並進一步傳播異常。如果bar()成功返回或導致未定義的行爲(因爲我不知道,其他東西已損壞),那麼foo()就可以。 foo()不能做任何事情,不應該關心bar()的未定義行爲。在這個意義上bar()是免費的,可以標記爲noexcept

所以我的問題是:什麼樣的語句可以在bar()認爲它是免費的這種感覺?

+7

先假設一切都可以拋出。那麼如果你需要證明它沒有。這是一個XY問題的味道。 –

+1

任何未定義的行爲都可能導致拋出異常...... –

+0

將'std :: vector :: at'包裝在try-catch中並沒有什麼意義。 – chris

回答

0

是的,可以用C++拋出的東西的列表可以被詳盡定義。

  • throw表達
  • new可以拋出bad_alloc
  • dynamic_cast可以拋出bad_cast
  • typeid可以拋出bad_typeid
  • 任何調用一個函數,不是noexceptthrow()

最後一點也適用於C++的所有隱式函數調用:default/copy/move構造函數,重載運算符,析構函數(注意那些默認爲noexcept)和轉換運算符。

如果您對特定表達式有疑問,可以使用noexcept運算符讓編譯器告訴您表達式在理論上是否可能拋出。

0

您的列表已基本完成。確實可以拋出一個演員陣容:dynamic_cast<Derived&>。這是因爲沒有空引用。 dynamic_cast<Derived*>返回空指針而不是拋出。

全部個案中,在評估表達式時引發例外。變量定義只有在包含表達式時纔會拋出,例如在初始化程序或構造函數中。

「未定義行爲」位是紅色鯡魚。你根本無法推理出一個具有未定義行爲的C++程序,甚至不能理解在該UB之前可能發生的事情。這意味着,只要我們推理定義的C++行爲,我們就不會假設UB。

0

答案很簡單:任何使用可重載操作符或函數的語句都不能被證明不會拋出。下面是一些例子:

template <class T> T foo(const T& arg) { return arg; } //can throw (copy constructor!) 
template <class T> void foo(T a, T b) { a+b; } //can throw (+ is overloadable) 

template <class T> 
void foo(T iter, T end) { 
    for(; iter < end; iter++) { //both the < and the ++ operator can throw 
     iter->bar(); //even the -> operator is overloadable and can throw 
    } 
} 

總之,只要你沒有參與類型的知識,一般是用模板的情況下,你很可能已經調用任何聲明投擲聲明。

Afaik,唯一有效的防禦措施,不允許例外。

相關問題