通過 const 引用按值捕獲的最佳實踐
一般來說,按值(而不是通過指標)丟擲是一種好的做法,但是通過(const)引用來捕獲。
try {
// throw new std::runtime_error("Error!"); // Don't do this!
// This creates an exception object
// on the heap and would require you to catch the
// pointer and manage the memory yourself. This can
// cause memory leaks!
throw std::runtime_error("Error!");
} catch (const std::runtime_error& e) {
std::cout << e.what() << std::endl;
}
通過引用捕獲是一個好的做法的一個原因是它消除了在傳遞給 catch 塊時(或當傳播到其他 catch 塊時)重構物件的需要。通過引用捕獲還允許以多型方式處理異常並避免物件切片。但是,如果要重新丟擲異常(如 throw e;
,請參見下面的示例),你仍然可以獲得物件切片,因為 throw e;
語句會根據宣告的型別生成異常的副本:
#include <iostream>
struct BaseException {
virtual const char* what() const { return "BaseException"; }
};
struct DerivedException : BaseException {
// "virtual" keyword is optional here
virtual const char* what() const { return "DerivedException"; }
};
int main(int argc, char** argv) {
try {
try {
throw DerivedException();
} catch (const BaseException& e) {
std::cout << "First catch block: " << e.what() << std::endl;
// Output ==> First catch block: DerivedException
throw e; // This changes the exception to BaseException
// instead of the original DerivedException!
}
} catch (const BaseException& e) {
std::cout << "Second catch block: " << e.what() << std::endl;
// Output ==> Second catch block: BaseException
}
return 0;
}
如果你確定不打算更改異常(例如新增資訊或修改訊息),那麼使用 const 引用可以使編譯器進行優化並提高效能。但這仍然會導致物件拼接(如上例所示)。
警告: 小心在 catch
塊中丟擲意外異常,尤其是與分配額外記憶體或資源有關。例如,構造 logic_error
,runtime_error
或它們的子類可能會因複製異常字串時記憶體耗盡而丟失 bad_alloc
,I / O 流可能會在日誌記錄期間丟擲相應的異常掩碼集等。