C++ Boost Exception超详细讲解

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。

到此这篇关于C++ Boost Exception超详细讲解的文章就介绍到这了,更多相关C++ Boost Exception内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost log日志库超详细讲解

    目录 一.说明 二.库Boost.Log 一.说明 应用程序库是指通常专门用于独立应用程序开发而不用于库开发的库. Boost.Log 是一个日志库. Boost.ProgramOptions 是一个用于定义和解析命令行选项的库. Boost.Serialization 允许您序列化对象,例如,将它们保存到文件或从文件加载它们. Boost.Uuid 支持使用 UUID. 具体内容 62. Boost.Log 63. Boost.ProgramOptions 64. Boost.Serializ

  • C++ Boost ProgramOptions超详细讲解

    目录 一.说明 二.示例Boost.ProgramOptions 一.说明 Boost.ProgramOptions Boost.ProgramOptions 是一个可以轻松解析命令行选项的库,例如,控制台应用程序.如果您使用图形用户界面开发应用程序,命令行选项通常并不重要. 要使用 Boost.ProgramOptions 解析命令行选项,需要以下三个步骤: 定义命令行选项.您给它们命名并指定哪些可以设置为一个值.如果命令行选项被解析为键/值对,您还可以设置值的类型——例如,它是字符串还是数字

  • C++ Boost Random随机函数详解

    目录 一.说明 二.示例代码 一.说明 Boost.Random 库提供了许多随机数生成器,可让您决定应如何生成随机数.在 C++ 中,始终可以使用来自 cstdlib 的 std::rand() 生成随机数.但是,使用 std::rand() 生成随机数的方式取决于标准库的实现方式. 当包含头文件 boost/random.hpp 时,您可以使用 Boost.Random 中的所有随机数生成器和其他类和函数. 该库的大部分已添加到 C++11 的标准库中.如果您的开发环境支持 C++11,您可

  • C++ Boost Accumulators累加器详细讲解

    Boost.Accumulators Boost.Accumulators 提供了处理样本的类.例如,您可以找到最大或最小的样本,或者计算所有样本的总和.虽然标准库支持其中一些操作,但 Boost.Accumulators 还支持统计计算,例如均值和标准差. 该库称为 Boost.Accumulators,因为累加器是一个基本概念.累加器是一个容器,每次插入一个值时都会计算出一个新的结果.该值不一定存储在累加器中.相反,累加器在输入新值时不断更新中间结果. Boost.Accumulators

  • C++ Boost Archive超详细讲解

    目录 一.说明 二.关于Archive库 一.说明 对Boost.Serialization库的应用,存在如下内容: Archive Pointers and References Serialization of Class Hierarchy Objects Wrapper Functions for Optimization Boost.Serialization 库可以将 C++ 程序中的对象转换为可以保存和加载以恢复对象的字节序列.有不同的数据格式可用于定义生成字节序列的规则. Boo

  • C++ Boost Uuid超详细讲解

    目录 一.说明 二.Boost.Uuid库示例和代码 一.说明 Boost.Uuid 为 UUID 提供生成器. UUID 是不依赖于中央协调实例的通用唯一标识符.例如,没有数据库存储所有生成的 UUID,可以检查这些 UUID 是否使用了新的 UUID. UUID 由必须唯一标识组件的分布式系统使用.例如,Microsoft 使用 UUID 来识别 COM 世界中的接口.对于为 COM 开发的新接口,可以轻松分配唯一标识符. UUID 是 128 位数字.存在多种生成 UUID 的方法.例如,

  • C++ Boost Conversion超详细讲解

    目录 一.说明 二.示例和代码 三.更多示例代码 一.说明 Boost.Conversion 在头文件 boost/cast.hpp 中定义了转换运算符 boost::polymorphic_cast 和 boost::polymorphic_downcast.它们旨在更精确地处理类型转换——通常使用 dynamic_cast 完成. 库由两个文件组成.分别在boost/cast.hpp文件中定义了boost::polymorphic_cast和boost::polymorphic_downca

  • C++ Boost System超详细讲解

    目录 一.说明 二.关于 Boost.System库 一.说明 以下库支持错误处理. Boost.System 提供类来描述和识别错误.自 C++11 以来,这些类已成为标准库的一部分. Boost.Exception 使得在抛出异常后附加数据成为可能. 二.关于 Boost.System库 Boost.System Boost.System 是一个库,本质上定义了四个类来识别错误.所有四个类都已添加到 C++11 的标准库中.如果您的开发环境支持 C++11,则无需使用 Boost.Syste

  • C++ Boost Exception超详细讲解

    Boost.Exception 库提供了一种新的异常类型 boost::exception,它允许您在抛出异常后将数据添加到异常中.此类型在 boost/exception/exception.hpp 中定义.由于 Boost.Exception 将其类和函数分布在多个头文件中,以下示例访问主头文件 boost/exception/all.hpp 以避免一个接一个地包含头文件. Boost.Exception 支持 C++11 标准的机制,该机制将异常从一个线程传输到另一个线程. boost::

  • C++ Boost Lockfree超详细讲解使用方法

    目录 一.说明 二.示例和代码 Boost.Lockfree 一.说明 Boost.Lockfree 提供线程安全和无锁容器.可以从多个线程访问此库中的容器,而无需同步访问. 在 1.56.0 版本中,Boost.Lockfree 只提供了两个容器:boost::lockfree::queue 类型的队列和 boost::lockfree::stack 类型的栈.对于队列,可以使用第二个实现:boost::lockfree::spsc_queue.此类针对只有一个线程写入队列和只有一个线程从队列

  • C++ Boost ScopeExit超详细讲解

    目录 一.提要 二.退出作用域(Boost.ScopeExit) 2.1 范例1.UsingBOOST_SCOPE_EXIT 2.2 示例2.Boost.ScopeExit和C++11的lambda函数 2.3 示例3.特点BOOST_SCOPE_EXIT 三.练习 一.提要 资源有很多种,每种都封装一套,还是挺繁琐的!对于比较少使用或者一个程序很可能只会用一次的资源,我们不想封装,在这种情况下用Boost.ScopeExit. 二.退出作用域(Boost.ScopeExit) 库 Boost.

  • C++ Boost Utility超详细讲解

    目录 一.说明 二.Boost.Utility库示例和代码 一.说明 Boost.Utility 库是杂项.有用的类和函数的集合,它们太小而无法在独立库中维护.虽然实用程序很小并且可以快速学习,但它们完全无关.与其他章节中的示例不同,此处的代码示例不是相互构建的,因为它们是独立的实用程序. 虽然大多数实用程序都在 boost/utility.hpp 中定义,但有些实用程序有自己的头文件.以下示例包括所介绍的实用程序的相应头文件. 二.Boost.Utility库示例和代码 示例 69.1.使用

  • C++ Boost Assign超详细讲解

    目录 说明 Exercise 说明 Boost.Assign Boost.Assign 库提供了帮助函数来初始化容器或向容器添加元素.如果需要将许多元素存储在一个容器中,这些函数尤其有用.多亏了 Boost.Assign 提供的函数,您不需要重复调​​用像 push_back() 这样的成员函数来将元素一个一个地插入到容器中. 如果您使用支持 C++11 的开发环境,则可以从初始化列表中获益.通常您可以将任意数量的值传递给构造函数来初始化容器.多亏了初始化列表,你不必依赖 C++11 的 Boo

  • C++ Boost Format超详细讲解

    Boost.Format Boost.Format 提供了函数 std::printf() 的替代品. std::printf() 源自 C 标准并允许格式化数据输出.但是,它既不是类型安全的,也不是可扩展的. Boost.Format 提供了一种类型安全且可扩展的替代方案. Boost.Format 提供了一个名为 boost::format 的类,该类在 boost/format.hpp 中定义.与 std::printf() 类似,将包含用于控制格式的特殊字符的字符串传递给 boost::

随机推荐