C++“准”标准库Boost学习指南(3):Boost.Utility

Boost.Utility

一些本不应在一个库里出现的有用的东西,只是因为它们每个都不太复杂和广泛,不足够形成一个单独的库。但不是说它们没有什么用外;事实上小的工具通常都有最广泛的用处。在Boost, 这些小工具被集中起来,形成一个称为Utility的库。你可以在这找到checked_delete, 一个函数,用于确认在删除点的类型是完整的;还有类noncopyable,用于确保类不能被复制;还有enable_if,用于对函数重载的完全控制。

Utility 库如何改进你的程序?
  • 编译期断言 BOOST_STATIC_ASSERT
  • 安全的析构 checked_delete 和 checked_array_delete
  • 禁止复制 noncopyable
  • operator&被重载时用 addressof取得对象地址
  • 用enable_if 和 disable_if控制重载与特化

有些工具还不够组成它们自己的库,因此它们与其它实体被集合到一起。这就形成了 Boost.Utility,收集了一些没有更合适地方存放的、有用的工具。它们很有用,应该被加入到Boost,但它们又太小,不足以形成自己的库。本文介绍Boost.Utility中最基本的以及最广泛使用的工具。

我们将从 BOOST_STATIC_ASSERT开始,它是一个在编译期判断整型常量表达式的工具。然后,我们看看当你通过一个指向不完整类型的指针delete对象时,即当被删除的对象的内存布局未知时,会发生什么。checked_delete 使得这个讨论更为有趣。我们还会看到 noncopyable 如何防止一个类被复制,这也是本章最重要的主题。然后我们将看到 addressof, 它用于阻止那些重载了operator&的险恶的程序员的病态行为。最后,我们将测试 enable_if, 它非常有用,可用于在名字查找时控制函数重载与模板特化是否被考虑。


BOOST_STATIC_ASSERT

头文件: "boost/static_assert.hpp"

在运行期执行断言可能是你经常用到的,也是非常合理的。它是测试前置条件、后置条件以及不变式的好方法。执行运行期断言有很多不同的方法,但是在编译期你如何进行断言呢?当然,唯一的方法就是让编译器产生一个错误,这是很平常的事情(我在无意中都做过几千次了),但如何从错误信息中获得有意义的信息却不是那么明显的。而且,即使你在一个编译器上找到了办法,也很难把它移植到其它编译器上。这就是使用 BOOST_STATIC_ASSERT的原因。它可以在不同的平台上使用,正如我们即将看到的。

用法

要开始使用静态断言,就要包含头文件 "boost/static_assert.hpp". 该头文件定义了宏BOOST_STATIC_ASSERT. 作为它的第一个使用范例,我们来看看如何在类作用域中使用它。考虑一个泛化的类,它要求实例化时所用的类型是一个整数类型。我们不想为所有类型提供特化,因此我们需要在编译期进行测试,以确保我们的类的确是用一个整数类型进行实例化的。现在,我们先提前一点使用另一个Boost库来进行测试,它就是 Boost.Type_traits. 我们使用一个称为is_integral的断言,它对它的参数执行一个编译期求值,正如你从它的名字可以猜到的一样,求值的结果是表明该类型是否一个整数类型。

#include <iostream>

#include "boost/type_traits.hpp"
#include "boost/static_assert.hpp"

template <typename T> class only_compatible_with_integral_types {
  BOOST_STATIC_ASSERT(boost::is_integral<T>::value);
};


有了这个断言,在实例化类 only_compatible_with_integral_types 时如果试图使用一个非整型的类型,就会导致一个编译期的失败。输出信息取决于编译器,但在多数编译器下输出信息会惊人地一致。

假设我们试图这样实例化:

  1. only_compatible_with_integral_types<double> test2;
编译器将会有类似下面的输出:
Error: use of undefined type
  'boost::STATIC_ASSERTION_FAILURE<false>'

在类的作用域里,你可以明确类的要求:象在前面这样的模板中明确参数的类型就是一个明显的例子。你也可以使用断言来明确类所要求的其它前提条件,如类型的大小等等。

函数作用域中的BOOST_STATIC_ASSERT

BOOST_STATIC_ASSERT 也可以用在函数作用域中。例如,考虑一个泛化的函数,它带有一个非类型模板参数,并且该参数只接受1至10的值。与其在运行期执行断言,我们不如在编译器使用静态断言。

template <int i> void accepts_values_between_1_and_10() {
  BOOST_STATIC_ASSERT(i>=1 && i<=10);
}


该函数的用户不能使用超出允许范围的数值来实例化这个函数。当然,断言中的表达式必须是一个纯粹的编译期表达式,也就是说,表达式中的参数和操作符都必须被编译器所认识。BOOST_STATIC_ASSERT 当然并不是只能用于泛型函数;我们可以在任何函数中很方便地测试条件。例如,一个函数需要一个与平台相关的前提条件,就常常需要一个断言。

void expects_ints_to_be_4_bytes() {
  BOOST_STATIC_ASSERT(sizeof(int)==4);
}


总结

你所看到的这种静态断言在C++中正变得象运行期断言assert那样常用。这应该至少部分地归功于"元编程革命",它使得一个程序中更多的计算量在编译期执行。表达编译期断言的唯一方法就是让编译器产生一个错误。为了让断言可用,错误提示必须可以传达有用的信息,但这很难做到可移植(事实上,根本不可能做到)。这正是 BOOST_STATIC_ASSERT 所要做的,它在大多数的编译器下提供了编译期断言的一致输出。它可用于名字空间、类、函数以及作用域。

以下情形下使用 BOOST_STATIC_ASSERT :

  • 当条件可以在编译期进行求值
  • 对类型的要求可以在编译期表示
  • 你需要对两个或以上的整型常量间的关系进行断言

checked_delete

头文件: "boost/checked_delete.hpp"

通过指针来删除一个对象时,执行的结果取决于执行删除时被删除的类型是否可知。对一个指向不完整类型的指针执行delete几乎不可能有编译器警告,这会导致各种各样的麻烦,由于析构函数可以没有被执行。换句话说,即进行清除的代码没有被执行。checked_delete 在对象析构时执行一个静态断言,测试类是否可知,以确保析构函数被执行。

用法

checked_delete 是一个boost名字空间中的模板函数。它用于删除动态分配的对象,对于动态分配的数组,同样有一个称为 checked_array_delete的模板函数。这些函数接受一个参数:要删除的指针,或是要删除的数组。这两个函数都要求在销毁对象时(即对象被传给函数时),这些被删除的类型必须是可知的。使用这些函数,要包含头文件"boost/checked_delete.hpp". 使用这些函数时,你只需象调用delete那样简单地调用它们。以下程序前向声明了一个类some_class, 而没有定义它。有些编译器允许对一个指向 some_class 的指针被删除(稍后再讨论这个),但使用 checked_delete 后,就不能通过编译了,除非有一个 some_class 的定义。

#include "boost/checked_delete.hpp"

class some_class;

some_class* create() {
  return (some_class*)0;
}

int main() {
  some_class* p=create();
  boost::checked_delete(p2);
}


如果你试图编译这段代码,对函数 checked_delete<some_class> 的实例化将失败,因为 some_class 是一个不完整的类型。你的编译器会输出类似下面的信息:

checked_delete.hpp: In function 'void
boost::checked_delete(T*) [with T = some_class]':
checked_sample.cpp:11:   instantiated from here
boost/checked_delete.hpp:34: error: invalid application of 'sizeof' to an incomplete type
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值