[英]How to handle runtime errors in C++?
所以,我對 C++ 有點陌生,我想知道什么是好的做法,甚至在編程時如何處理運行時錯誤,這里有一個例子:
State s_toState(std::string state){
if (state == "MG")
return State::MG;
else if (state == "PR")
return State::PR;
else if (state == "SP")
return State::SP;
else if (state == "SC")
return State::SC;
else if (state == "RJ")
return State::RJ;
else if (state == "RN")
return State::RN;
else if (state == "RS")
return State::RS;
// ???
}
所以我有這個 function 將string
轉換為State
。 在不使用異常的情況下,我斷言給定的 state 是現有的(MG、PR、SP 等)的理想方法是什么?
舉個例子,但我要求的是一般規則。 據我所知,我可以使用異常、斷言或只打印錯誤。 我也假裝對此進行單元測試(也是單元測試的新手,對此一無所知)。
這看起來是一個使用異常的好機會。 cplusplus.com 指南是合理的,但我發現玩弄它是一種更好的學習方式。
基本思想是這樣的:
throw
異常,終止 function 並將異常傳遞給調用 function 的任何人。try
塊中調用了 function,那么接下來的catch
就會被執行。try
/ catch
系統,則調用者也會被終止,並且該過程會重復 function 調用堆棧,直到找到try
/ catch
或main()
終止。 答案取決於s_toState
“承諾”要做什么。
如果state
無效是 function 或其他內部邏輯錯誤的程序員的錯誤。 添加assert
並記錄 state 有效性作為前提條件(與指針的!=nullptr
相同)。 對於發布版本,添加一些默認行為,這樣程序就不會在可能的情況下崩潰。 或者如果你不寫關鍵的軟件就讓它崩潰,它至少會使調試更容易。
如果它是用戶的可恢復錯誤和合理的場景(不是錯誤),則考慮返回std::optional
或throw
。 當拋出的異常總是被直接調用者捕獲時,我更喜歡前者,即從不向上傳播調用堆棧。 我也發現它更清楚,因為它強制調用者明確處理它。
對於不可恢復的錯誤,即當直接調用者無法處理nullopt
時,只需拋出並讓其他代碼處理即可。
我喜歡try_parse
返回std::optional
的命名約定,同時parse
拋出。
嘗試一下異常和錯誤處理常見問題解答可能是值得的。
一般來說,處理此類錯誤(如任何錯誤)的方式取決於整個程序的需求 - 而您尚未指定。 所以沒有一刀切的“一般規則”。
有選擇和權衡。
一種選擇是為您的State
枚舉類型提供表示未確定或無效 state 的枚舉器值,例如
enum class State {MG, PR, Undetermined};
然后,在您的 function 中,返回未確定的值,例如
State s_toState(const std::string &state)
{
State return_value = State::Undetermined;
if (state == "MG")
return_value = State::MG;
else if (state == "PR")
return_value = State::PR;
// etc
return return_value;
}
使用這種方法, function 始終返回State
類型的有效值。 如果錯誤條件不是很嚴重(即如果提供了無效字符串,程序可以繼續),那么調用者可以決定是否需要檢查返回值。 可以報告多種類型的錯誤條件(例如,通過具有表示不同錯誤的多個枚舉值)不利的一面是調用者可能忘記檢查返回值並且行為不正確。
另一種選擇是拋出異常,例如;
State s_toState(const std::string &state)
{
if (state == "MG")
return State::MG;
else if (state == "PR")
return State::PR;
// etc
throw std::invalid_argument("Bad input string");
}
這個選項需要對拋出什么類型的異常做出明智的選擇(例如,需要傳達關於錯誤狀態的什么信息)。 如果提供了錯誤的字符串,調用者(或整個程序)無法合理地繼續,則此方法可能更可取,因為通過拋出異常,調用者被迫捕獲並采取任何恢復操作以避免被終止。 因此,這種方法可能不適用於非關鍵錯誤——例如,如果提供了錯誤的字符串,則可以合理地繼續執行。
另一種選擇(C++17 及更高版本)是返回std::optional<State>
。 這允許調用者檢查是否發生了錯誤(例如std::option::has_value()
return false
),或者,如果在沒有檢查的情況下訪問該值,則導致拋出std::bad_optional_access
類型的異常(其中可能適合呼叫者,或者可能不提供信息)。
也可以使用assert()
- 如果指定的條件不正確,它會強制終止。 通常,我更喜歡使用assert()
拋出異常,但您可能更喜歡其他方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.