C++ Boost Exception超詳細講解
Boost.Exception 庫提供了一種新的異常類型 boost::exception,它允許您在拋出異常后將數(shù)據(jù)添加到異常中。此類型在 boost/exception/exception.hpp 中定義。由于 Boost.Exception 將其類和函數(shù)分布在多個頭文件中,以下示例訪問主頭文件 boost/exception/all.hpp 以避免一個接一個地包含頭文件。
Boost.Exception 支持 C++11 標(biāo)準(zhǔn)的機制,該機制將異常從一個線程傳輸?shù)搅硪粋€線程。 boost::exception_ptr 類似于 std::exception_ptr。但是,Boost.Exception 并不能完全替代標(biāo)準(zhǔn)庫中的頭文件異常。例如,Boost.Exception 缺少對 std::nested_exception 類型的嵌套異常的支持。
注意
要使用 Visual C++ 2013 編譯本章中的示例,請刪除關(guān)鍵字 noexcept。此版本的 Microsoft 編譯器尚不支持 noexcept。
示例 56.1。使用 boost::exception
#include <boost/exception/all.hpp> #include <exception> #include <new> #include <string> #include <algorithm> #include <limits> #include <iostream> typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info; struct allocation_failed : public boost::exception, public std::exception { const char *what() const noexcept { return "allocation failed"; } }; char *allocate_memory(std::size_t size) { char *c = new (std::nothrow) char[size]; if (!c) throw allocation_failed{}; return c; } char *write_lots_of_zeros() { try { char *c = allocate_memory(std::numeric_limits<std::size_t>::max()); std::fill_n(c, std::numeric_limits<std::size_t>::max(), 0); return c; } catch (boost::exception &e) { e << errmsg_info{"writing lots of zeros failed"}; throw; } } int main() { try { char *c = write_lots_of_zeros(); delete[] c; } catch (boost::exception &e) { std::cerr << boost::diagnostic_information(e); } }
示例 56.1 調(diào)用函數(shù) write_lots_of_zeros(),該函數(shù)又調(diào)用 allocate_memory()。 allocate_memory() 動態(tài)分配內(nèi)存。該函數(shù)將 std::nothrow 傳遞給 new 并檢查返回值是否為 0。如果內(nèi)存分配失敗,則會拋出 allocation_failed 類型的異常。如果 new 分配內(nèi)存失敗,allocation_failed 替換默認拋出的異常 std::bad_alloc 。
write_lots_of_zeros() 調(diào)用 allocate_memory() 以嘗試分配最大可能大小的內(nèi)存塊。這是在 std::numeric_limits 的 max() 的幫助下完成的。該示例故意嘗試分配那么多內(nèi)存以使分配失敗。
allocation_failed 源自 boost::exception 和 std::exception。不需要從 std::exception 派生類。 allocation_failed 也可以派生自不同類層次結(jié)構(gòu)的類,以便將其嵌入現(xiàn)有框架中。雖然示例 56.1 使用標(biāo)準(zhǔn)定義的類層次結(jié)構(gòu),但僅從 boost::exception 派生 allocation_failed 就足夠了。
如果捕獲到 allocation_failed 類型的異常,allocate_memory() 必須是異常的來源,因為它是唯一拋出此類異常的函數(shù)。在有許多函數(shù)調(diào)用 allocate_memory() 的程序中,知道異常的類型不再足以有效地調(diào)試程序。在這些情況下,了解哪個函數(shù)試圖分配比 allocate_memory() 所能提供的更多的內(nèi)存會有所幫助。
挑戰(zhàn)在于 allocate_memory() 沒有任何附加信息,例如調(diào)用者姓名,可以添加到異常中。 allocate_memory() 無法豐富異常。這只能在調(diào)用上下文中完成。
使用 Boost.Exception,可以隨時將數(shù)據(jù)添加到異常中。您只需為需要添加的每一位數(shù)據(jù)定義一個基于 boost::error_info 的類型。
boost::error_info 是一個需要兩個參數(shù)的模板。第一個參數(shù)是一個標(biāo)簽,用于唯一標(biāo)識新創(chuàng)建的類型。這通常是具有唯一名稱的結(jié)構(gòu)。第二個參數(shù)是指存儲在異常中的值的類型。示例 56.1 定義了一個新類型 errmsg_info——通過結(jié)構(gòu) tag_errmsg 唯一標(biāo)識——它存儲一個 std::string 類型的字符串。
在 write_lots_of_zeros() 的捕獲處理程序中,errmsg_info 用于創(chuàng)建一個用字符串“寫入大量零失敗”初始化的對象。然后使用 operator<< 將該對象添加到 boost::exception 類型的異常中。然后異常被重新拋出。
現(xiàn)在,異常不僅僅表示內(nèi)存分配失敗。它還表示,當(dāng)程序試圖在函數(shù) write_lots_of_zeros() 中寫入大量零時,內(nèi)存分配失敗。知道哪個函數(shù)稱為 allocate_memory() 可以更輕松地調(diào)試較大的程序。
要從異常中檢索所有可用數(shù)據(jù),可以在 main() 的捕獲處理程序中調(diào)用函數(shù) boost::diagnostic_information()。 boost::diagnostic_information() 為傳遞給它的每個異常調(diào)用成員函數(shù) what() 并訪問存儲在異常中的所有附加數(shù)據(jù)。 boost::diagnostic_information() 返回一個 std::string 類型的字符串,例如,它可以寫入標(biāo)準(zhǔn)錯誤。
當(dāng)使用 Visual C++ 2013 編譯時,示例 56.1 將顯示以下消息:
Throw location unknown (consider using BOOST_THROW_EXCEPTION)
Dynamic exception type: struct allocation_failed
std::exception::what: allocation failed
[struct tag_errmsg *] = writing lots of zeros failed
該消息包含異常類型、從 what() 檢索到的錯誤消息以及描述,包括結(jié)構(gòu)名稱。
boost::diagnostic_information() 在運行時檢查給定異常是否源自 std::exception。 what() 只有在這種情況下才會被調(diào)用。
拋出 allocation_failed 類型異常的函數(shù)名稱未知。
Boost.Exception 提供了一個宏來拋出異常,該異常不僅包含函數(shù)名,還包含文件名和行號等附加數(shù)據(jù)。
示例 56.2。更多數(shù)據(jù)與 BOOST_THROW_EXCEPTION
#include <boost/exception/all.hpp> #include <exception> #include <new> #include <string> #include <algorithm> #include <limits> #include <iostream> typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info; struct allocation_failed : public std::exception { const char *what() const noexcept { return "allocation failed"; } }; char *allocate_memory(std::size_t size) { char *c = new (std::nothrow) char[size]; if (!c) BOOST_THROW_EXCEPTION(allocation_failed{}); return c; } char *write_lots_of_zeros() { try { char *c = allocate_memory(std::numeric_limits<std::size_t>::max()); std::fill_n(c, std::numeric_limits<std::size_t>::max(), 0); return c; } catch (boost::exception &e) { e << errmsg_info{"writing lots of zeros failed"}; throw; } } int main() { try { char *c = write_lots_of_zeros(); delete[] c; } catch (boost::exception &e) { std::cerr << boost::diagnostic_information(e); } }
使用宏 BOOST_THROW_EXCEPTION 代替 throw,函數(shù)名、文件名和行號等數(shù)據(jù)會自動添加到異常中。但這僅在編譯器支持附加數(shù)據(jù)的宏時才有效。雖然 __FILE__ 和 __LINE__ 等宏自 C++98 以來就已標(biāo)準(zhǔn)化,但獲取當(dāng)前函數(shù)名稱的宏 __func__ 僅在 C++11 中成為標(biāo)準(zhǔn)。由于許多編譯器在 C++11 之前提供了這樣的宏,BOOST_THROW_EXCEPTION 會嘗試識別底層編譯器并使用相應(yīng)的宏(如果存在)。
使用 Visual C++ 2013 編譯,示例 56.2 顯示以下消息:
main.cpp(20): Throw in function char *__cdecl allocate_memory(unsigned int)
Dynamic exception type: class boost::exception_detail::clone_impl<struct boost::exception_detail::error_info_injector<struct allocation_failed> >
std::exception::what: allocation failed
[struct tag_errmsg *] = writing lots of zeros failed
在示例 56.2 中,allocation_failed 不再派生自 boost::exception。 BOOST_THROW_EXCEPTION 訪問函數(shù) boost::enable_error_info(),它標(biāo)識異常是否源自 boost::exception。如果不是,它會創(chuàng)建一個從指定類型和 boost::exception 派生的新異常類型。這就是為什么上面顯示的消息包含與 allocation_failed 不同的異常類型。
示例 56.3。使用 boost::get_error_info() 有選擇地訪問數(shù)據(jù)
#include <boost/exception/all.hpp> #include <exception> #include <new> #include <string> #include <algorithm> #include <limits> #include <iostream> typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info; struct allocation_failed : public std::exception { const char *what() const noexcept { return "allocation failed"; } }; char *allocate_memory(std::size_t size) { char *c = new (std::nothrow) char[size]; if (!c) BOOST_THROW_EXCEPTION(allocation_failed{}); return c; } char *write_lots_of_zeros() { try { char *c = allocate_memory(std::numeric_limits<std::size_t>::max()); std::fill_n(c, std::numeric_limits<std::size_t>::max(), 0); return c; } catch (boost::exception &e) { e << errmsg_info{"writing lots of zeros failed"}; throw; } } int main() { try { char *c = write_lots_of_zeros(); delete[] c; } catch (boost::exception &e) { std::cerr << *boost::get_error_info<errmsg_info>(e); } }
示例 56.3 沒有使用 boost::diagnostic_information(),它使用 boost::get_error_info() 直接訪問 errmsg_info 類型的錯誤消息。因為 boost::get_error_info() 返回類型為 boost::shared_ptr 的智能指針,所以 operator* 用于獲取錯誤消息。如果傳遞給 boost::get_error_info() 的參數(shù)不是 boost::exception 類型,則返回空指針。如果宏 BOOST_THROW_EXCEPTION 始終用于拋出異常,則異常將始終從 boost::exception 派生——在這種情況下無需檢查返回的智能指針是否為 null。
到此這篇關(guān)于C++ Boost Exception超詳細講解的文章就介紹到這了,更多相關(guān)C++ Boost Exception內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ Boost Coroutine使用協(xié)程詳解
通過Boost.Coroutine,可以在C++中使用協(xié)程。協(xié)程是其他編程語言的一個特性,通常使用關(guān)鍵字yield來表示協(xié)程。在這些編程語言中,yield可以像return一樣使用2022-11-11Visual Studio 2022最新版安裝教程(圖文詳解)
本文主要介紹了Visual Studio 2022最新版安裝教程,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01C++函數(shù)參數(shù)匹配規(guī)則示例小結(jié)
這篇文章主要介紹了C++函數(shù)參數(shù)匹配規(guī)則,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08關(guān)于c++11與c風(fēng)格路徑拼接的速度對比
這篇文章主要介紹了關(guān)于c++11與c風(fēng)格路徑拼接的速度對比分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07