日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++?Boost?Exception超詳細講解_C 語言

作者:無水先生 ? 更新時間: 2022-12-23 編程語言

Boost.Exception 庫提供了一種新的異常類型 boost::exception,它允許您在拋出異常后將數據添加到異常中。此類型在 boost/exception/exception.hpp 中定義。由于 Boost.Exception 將其類和函數分布在多個頭文件中,以下示例訪問主頭文件 boost/exception/all.hpp 以避免一個接一個地包含頭文件。

Boost.Exception 支持 C++11 標準的機制,該機制將異常從一個線程傳輸到另一個線程。 boost::exception_ptr 類似于 std::exception_ptr。但是,Boost.Exception 并不能完全替代標準庫中的頭文件異常。例如,Boost.Exception 缺少對 std::nested_exception 類型的嵌套異常的支持。

注意

要使用 Visual C++ 2013 編譯本章中的示例,請刪除關鍵字 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);
  }
}

Example56.1

示例 56.1 調用函數 write_lots_of_zeros(),該函數又調用 allocate_memory()。 allocate_memory() 動態分配內存。該函數將 std::nothrow 傳遞給 new 并檢查返回值是否為 0。如果內存分配失敗,則會拋出 allocation_failed 類型的異常。如果 new 分配內存失敗,allocation_failed 替換默認拋出的異常 std::bad_alloc 。

write_lots_of_zeros() 調用 allocate_memory() 以嘗試分配最大可能大小的內存塊。這是在 std::numeric_limits 的 max() 的幫助下完成的。該示例故意嘗試分配那么多內存以使分配失敗。

allocation_failed 源自 boost::exception 和 std::exception。不需要從 std::exception 派生類。 allocation_failed 也可以派生自不同類層次結構的類,以便將其嵌入現有框架中。雖然示例 56.1 使用標準定義的類層次結構,但僅從 boost::exception 派生 allocation_failed 就足夠了。

如果捕獲到 allocation_failed 類型的異常,allocate_memory() 必須是異常的來源,因為它是唯一拋出此類異常的函數。在有許多函數調用 allocate_memory() 的程序中,知道異常的類型不再足以有效地調試程序。在這些情況下,了解哪個函數試圖分配比 allocate_memory() 所能提供的更多的內存會有所幫助。

挑戰在于 allocate_memory() 沒有任何附加信息,例如調用者姓名,可以添加到異常中。 allocate_memory() 無法豐富異常。這只能在調用上下文中完成。

使用 Boost.Exception,可以隨時將數據添加到異常中。您只需為需要添加的每一位數據定義一個基于 boost::error_info 的類型。

boost::error_info 是一個需要兩個參數的模板。第一個參數是一個標簽,用于唯一標識新創建的類型。這通常是具有唯一名稱的結構。第二個參數是指存儲在異常中的值的類型。示例 56.1 定義了一個新類型 errmsg_info——通過結構 tag_errmsg 唯一標識——它存儲一個 std::string 類型的字符串。

在 write_lots_of_zeros() 的捕獲處理程序中,errmsg_info 用于創建一個用字符串“寫入大量零失敗”初始化的對象。然后使用 operator<< 將該對象添加到 boost::exception 類型的異常中。然后異常被重新拋出。

現在,異常不僅僅表示內存分配失敗。它還表示,當程序試圖在函數 write_lots_of_zeros() 中寫入大量零時,內存分配失敗。知道哪個函數稱為 allocate_memory() 可以更輕松地調試較大的程序。

要從異常中檢索所有可用數據,可以在 main() 的捕獲處理程序中調用函數 boost::diagnostic_information()。 boost::diagnostic_information() 為傳遞給它的每個異常調用成員函數 what() 并訪問存儲在異常中的所有附加數據。 boost::diagnostic_information() 返回一個 std::string 類型的字符串,例如,它可以寫入標準錯誤。

當使用 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() 檢索到的錯誤消息以及描述,包括結構名稱。

boost::diagnostic_information() 在運行時檢查給定異常是否源自 std::exception。 what() 只有在這種情況下才會被調用。

拋出 allocation_failed 類型異常的函數名稱未知。

Boost.Exception 提供了一個宏來拋出異常,該異常不僅包含函數名,還包含文件名和行號等附加數據。

示例 56.2。更多數據與 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,函數名、文件名和行號等數據會自動添加到異常中。但這僅在編譯器支持附加數據的宏時才有效。雖然 __FILE__ 和 __LINE__ 等宏自 C++98 以來就已標準化,但獲取當前函數名稱的宏 __func__ 僅在 C++11 中成為標準。由于許多編譯器在 C++11 之前提供了這樣的宏,BOOST_THROW_EXCEPTION 會嘗試識別底層編譯器并使用相應的宏(如果存在)。

使用 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 訪問函數 boost::enable_error_info(),它標識異常是否源自 boost::exception。如果不是,它會創建一個從指定類型和 boost::exception 派生的新異常類型。這就是為什么上面顯示的消息包含與 allocation_failed 不同的異常類型。

示例 56.3。使用 boost::get_error_info() 有選擇地訪問數據

#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);
  }
}

Example56.3

示例 56.3 沒有使用 boost::diagnostic_information(),它使用 boost::get_error_info() 直接訪問 errmsg_info 類型的錯誤消息。因為 boost::get_error_info() 返回類型為 boost::shared_ptr 的智能指針,所以 operator* 用于獲取錯誤消息。如果傳遞給 boost::get_error_info() 的參數不是 boost::exception 類型,則返回空指針。如果宏 BOOST_THROW_EXCEPTION 始終用于拋出異常,則異常將始終從 boost::exception 派生——在這種情況下無需檢查返回的智能指針是否為 null。

原文鏈接:https://yamagota.blog.csdn.net/article/details/128031598

欄目分類
最近更新