15.2. Boost.System

Boost.System 是一个定义了四个类的小型库,用以识别错误。 boost::system::error_code 是一个最基本的类,用于代表某个特定操作系统的异常。 由于操作系统通常枚举异常,boost::system::error_code 中以变量的形式保存错误代码 int。 下面的例子说明了如何通过访问 Boost.Asio 类来使用这个类。

  1. #include <boost/system/error_code.hpp>
  2. #include <boost/asio.hpp>
  3. #include <iostream>
  4. #include <string>
  5.  
  6. int main()
  7. {
  8. boost::system::error_code ec;
  9. std::string hostname = boost::asio::ip::host_name(ec);
  10. std::cout << ec.value() << std::endl;
  11. }

Boost.Asio 提供了独立的函数 boost::asio::ip::host_name() 可以返回正在执行的应用程序名。

boost::system::error_code 类型的一个对象可以作为单独的参数传递给 boost::asio::ip::host_name()。 如果当前的操作系统函数失败, 这个参数包含相关的错误代码。 也可以通过调用 boost::asio::ip::host_name() 而不使用任何参数,以防止错误代码是非相关的。

事实上在Boost 1.36.0中 boost::asio::ip::host_name() 是有问题的,然而它可以当作一个很好的例子。 即使当前操作系统函数成功返回了计算机名,这个函数它也可能返回一个错误代码。 由于在Boost 1.37.0中解决了这个问题,现在可以放心使用 boost::asio::ip::host_name() 了。

由于错误代码仅仅是一个数值,因此可以借助于 value() 方法得到它。 由于错误代码0通常意味着没有错误,其他的值的意义则依赖于操作系统并且需要查看相关手册。

如果使用Boost 1.36.0, 并且用Visual Studio 2008在Windows XP环境下编译以上应用程序将不断产生错误代码14(没有足够的存储空间以完成操作)。 即使函数 boost::asio::ip::host_name() 成功决定了计算机名,也会报出错误代码14。 事实上这是因为函数 boost::asio::ip::host_name() 的实现有问题。

除了 value() 方法之外, 类 boost::system::error_code 提供了方法 category()。 这个方法可返回一个在 Boost.System 中定义的二级对象: boost::system::category

错误代码是简单的数值。 操作系统开发商,例如微软,可以保证系统错误代码的特异性。 对于任何开发商来说,在所有现有应用程序中保持错误代码的独一无二是几乎不可能的。 他需要一个包含有所有软件开发者的错误代码中心数据库,以防止在不同的方案下重复使用相同的代码。 当然这是不实际的。 这是错误分类表存在的缘由。

类型 boost::system::errorcode 的错误代码总是属于可以使用 category() 方法获取的分类。 通过预定义的对象 _boost::system::system_category 来表示操作系统的错误。

通过调用 category() 方法,可以返回预定义变量 boost::system::system_category 的一个引用。 它允许获取关于分类的特定信息。 例如在使用的是 system 分类的情况下,通过使用 name() 方法将得到它的名字 system

  1. #include <boost/system/error_code.hpp>
  2. #include <boost/asio.hpp>
  3. #include <iostream>
  4. #include <string>
  5.  
  6. int main()
  7. {
  8. boost::system::error_code ec;
  9. std::string hostname = boost::asio::ip::host_name(ec);
  10. std::cout << ec.value() << std::endl;
  11. std::cout << ec.category().name() << std::endl;
  12. }

通过错误代码和错误分类识别出的错误是独一无二的。 由于仅仅在错误分类中的错误代码是必须唯一的,程序员应当在希望定义某个特定应用程序的错误代码时创建一个新的分类。 这使得任何错误代码都不会影响到其他开发者的错误代码。

  1. #include <boost/system/error_code.hpp>
  2. #include <iostream>
  3. #include <string>
  4.  
  5. class application_category :
  6. public boost::system::error_category
  7. {
  8. public:
  9. const char *name() const { return "application"; }
  10. std::string message(int ev) const { return "error message"; }
  11. };
  12.  
  13. application_category cat;
  14.  
  15. int main()
  16. {
  17. boost::system::error_code ec(14, cat);
  18. std::cout << ec.value() << std::endl;
  19. std::cout << ec.category().name() << std::endl;
  20. }

通过创建一个派生于 boost::system::error_category 的类以及实现作为新分类的所必须的接口的不同方法可以定义一个新的错误分类。 由于方法 name()message() 在类 boost::system::error_category 中被定义为纯虚拟函数,所以它们是必须提供的。 至于额外的方法,在必要的条件下,可以重载相对应的默认行为。

当方法 name() 返回错误分类名时,可以使用方法 message() 来获取针对某个错误代码的描述。 不像之前的那个例子,参数 ev 往往被用于返回基于错误代码的描述。

新创建的错误分类的对象可以被用来初始化相应的错误代码。 本例中定义了一个用于新分类 applicationcategory 的错误代码 _ec 。 然而错误代码14不再是系统错误;他的意义被开发者指定为新的错误分类。

boost::system::error_code 包含了一个叫作 default_error_condition() 的方法,它可以返回 boost::system::error_condition类型的对象。 boost::system::error_condition 的接口几乎与 boost::system::error_code 相同。 唯一的差别是只有类 boost::system::error_code 提供了方法 default_error_condition()

  1. #include <boost/system/error_code.hpp>
  2. #include <boost/asio.hpp>
  3. #include <iostream>
  4. #include <string>
  5.  
  6. int main()
  7. {
  8. boost::system::error_code ec;
  9. std::string hostname = boost::asio::ip::host_name(ec);
  10. boost::system::error_condition ecnd = ec.default_error_condition();
  11. std::cout << ecnd.value() << std::endl;
  12. std::cout << ecnd.category().name() << std::endl;
  13. }

boost::system::error_condition 的使用方法与 boost::system::error_code 类似。 对象boost::system::error_conditionvalue()category() 方法都可以像上面的例子中那样调用。

有或多或少两个相同的类的原因很简单:当类 boost::system::error_code 被当作当前平台的错误代码时, 类 boost::system::error_condition 可以被用作获取跨平台的错误代码。 通过调用 default_error_condition() 方法,可以把依赖于某个平台的的错误代码转换成 boost::system::error_condition 类型的跨平台的错误代码。

如果执行以上应用程序,它将显示数字12以及错误分类 GENERIC。 依赖于平台的错误代码14被转换成了跨平台的错误代码12。 借助于 boost::system::error_condition ,可以总是使用相同的数字表示错误,无视当前操作系统。 当Windows报出错误14时,其他操作系统可能会对相同的错误报出错误代码25。 使用 boost::system::error_condition ,总是对这个错误报出错误代码12。

最后 Boost.System 提供了类 boost::system::system_error ,它派生于 std::runtime_error。 它可被用来传送发生在异常里类型为 boost::system::error_code 的错误代码。

  1. #include <boost/asio.hpp>
  2. #include <boost/system/system_error.hpp>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. try
  8. {
  9. std::cout << boost::asio::ip::host_name() << std::endl;
  10. }
  11. catch (boost::system::system_error &e)
  12. {
  13. boost::system::error_code ec = e.code();
  14. std::cerr << ec.value() << std::endl;
  15. std::cerr << ec.category().name() << std::endl;
  16. }
  17. }

独立的函数 boost::asio::ip::host_name() 是以两种方式提供的:一种是需要类型为 boost::system::error_code 的参数,另一种不需要参数。 第二个版本将在错误发生时抛出 boost::system::system_error 类型的异常。 异常传出类型为 boost::system::error_code 的相应错误代码。