異常處理 Exception
在 C++ 中,異常 exception 是在程式執行期間發生的事件。它的出現會打斷正常的程式流程。一個常見的例子比如說程式嘗試將一個整數除以 0。我們都知道不能將數字除以 0,而程式碼遇到這樣的情況也會報錯並立即終止程式。但有時候,即使出現這樣的錯誤,我們還是希望程式碼可以繼續執行下去。
這就好比一場籃球比賽,當有人犯規的時候,球賽並不會因此而中止,反而裁判會吹哨並且處理判罰,處理完後再恢復比賽,讓比賽繼續。而異常處理的機制就是在扮演裁判的角色!
C++ 提供了處理異常的機制,讓我們可以在錯誤處理和程式控制流程上擁有更多的掌控權。這個機制提供了三個關鍵字:
try
:定義一塊程式代碼塊,英文叫做 try block。這個區塊會充當觀察者,負責找尋任何在這個區塊內發生的異常。throw
:當錯誤發生時,throw
就會丟出一個異常。catch
:當觀察到異常時,我們可以利用catch
來捕獲異常,並做出相對應的處理。
在程式碼中,異常處理的大致架構大概會長這樣:
try // 尋找異常 { // 丟出異常 throw } catch () { // 異常處理 }
接下來,我們來一個一個講他的功能!
丟出異常 throw
在 C++ 中,我們利用 throw
語句來丟出異常,表示程式偵測到錯誤了!利用先前的籃球比賽例子就是裁判看到有人犯規並吹哨了。而犯規也有很多種,有打手犯規、進攻犯規、防守犯規等等。每一種犯規裁判都會用不同的手勢。
在 C++ 中,我們丟出的異常也可以有很多種!比如說整數、字串、變數等等,甚至是更高階的物件(以後會講到)。比如說:
throw 0; // 整數 throw "This is an error"; // 字串 throw error; // 變數 throw MyClass(); // 物件
根據你的程式碼的應用,我們可以自己選擇想要丟出的異常種類,單看之後要怎麼處理這些異常。核心概念在於,每一個異常都代表著程式中出現了某種錯誤需要我們去解決。
尋找異常 try
在 C++ 中,我們利用 try
語句來偵測異常。同樣利用籃球比賽來舉例,當裁判吹哨並表示有人犯規時(丟出異常),場上的所有人都會因此停下動作,造成比賽暫時中斷。
try
在這裡就好比定義出球場上的人員,被定義在這個球場裡的所有人都必須時刻關注裁判有沒有吹哨(異常),如果偵測到了,那麼比賽(程式流程)必須因此中斷。
try { // ... 表示我們寫的其他程式碼 ... ... throw -1; ... } // 在這個 {} 裡面的都要注意什麼時候會丟出異常(在這個例子就是 -1)
處理異常 catch
在 C++ 中,我們利用 catch
語句來處理異常。當裁判吹哨表示有人犯規,球場的所有人都停下動作後,裁判這時候就要出來處理這個犯規了。可能是罰球、重新發球、交換球權等等,完全看裁判想怎麼處理。處理完後,球賽才會繼續執行。
catch
會馬上接在 try
後面,用來處理在 try
偵測到的各種異常。並且我們也可以根據不同種類的異常寫出不只一種處理方式。
catch(int e) { std::cout << "the error code is " << e << std::endl; } catch(string e) { std::cout << e << std::endl; }
在上面的例子我們可以看到兩個 catch
語句,分別處理不同類型的異常,第一個是整數型態,第二個則是字串型態。
這就像是根據不同的犯規,裁判會給出相應的判決一樣。這樣是不是很好理解!
如果說我們不想管那麼多呢?也就是不管偵測到什麼類型的異常,都只用一種方式處理。這也是可以做到的!我們可以這樣做:
catch(...) { std::cout << "An error has occured!"; }
大總匯
現在讓我們把三個語句全部串起來!在下面的例子中,我們判斷變數 a
是不是為 0,如果是的話就丟出異常,不是的話就執行除法。並針對不同類型的異常去做相對應的處理。處理完異常後,程式碼則會繼續進行下去,最後會印出 Continue...
。
如果想要讓這個例子更加實用,我們可以將變數 a
改為使用者輸入。但這邊只是一個示範,因此我們盡量讓範例簡單一些。
try { int a = 0; if (a == 0) { throw -1; } else { std::cout << 8/a << std::endl; } } catch(int e) { std::cout << "integer type: " << e << std::endl; } catch(float e) { std::cout << "float type: " << e << std::endl; } catch(std::string e) { std::cout << "string type: " << e << std::endl; } std::cout << "Continue..." << std::endl;
執行完上面這個程式後,我們會看到這樣的輸出:
integer type: -1 Continue...