促进 C++库

……其中一个世界。 赫伯·萨特安德烈亚历山德雷斯库,C类++编码标准

Boost实现变化

接口和实现的分离

boost.org库的接口规范组件(以及一般的质量软件)是从概念上与这些接口的实现分离。这可能不太明显,尤其是当组件完全在标头中实现,但始终假定接口和实现。软件设计相关人员的观点,接口的可移植性和标准化重要,而实现只是一个细节。

Dietmar Kühl,原始boost.org之一贡献者,评论“主要贡献是界面,它通过一个实现进行了扩充,证明它是可以实现相应的类并提供免费实施。"

实施变化

可能需要多个接口,以适应平台依赖性或性能权衡。平台依赖性示例包括编译器缺点、文件系统、线程机制、,和图形用户界面。一个经典的例子性能权衡是一种使用大量资源的快速实现与使用更少内存的较慢实现相比内存。

Boost库通常使用配置收割台,boost/config.hpp,用于捕获编译器和平台依赖关系。虽然boost/config.hpp的使用不是必需,这是简单配置的首选方法问题。

促进政策

Boost政策旨在避免依赖平台的变化在接口规范中,但提供的实现可用于多种平台和应用程序。这意味着boost库将使用以下技术描述为适用于处理平台依赖关系。

针对实施变化设计的推进政策要提高性能,就要避免它们,除非大大超过了全部成本。术语“全部成本”是旨在包括额外维护等有形成本,以及无形成本,如用户难度增加理解。

提供实现变化的技术

可以使用几种技术来实现变化。每种方法在某些情况下都适用,但不适用适用于其他情况。

单一通用实现

第一种技术是不提供实现完全不同。相反,提供一个通用的实现,并放弃所有其他技术。

适当的:当可以编写具有合理性能的单个可移植实现跨多种平台。特别适用于替代实现只在深奥的方式上有所不同。

不合适:实施时需要特定于平台的功能,或存在多个功能时可以实现不同的性能特点。

Beman Dawes评论道:“在设计讨论中实施通常被认为比另一个快得多,然而,时间测试没有发现显著差异。这个经验是,虽然算法差异可能会影响速度引人注目的是,编码差异,例如从虚拟到非虚拟成员或删除级别间接不太可能产生任何可测量的差异除非深入内部循环。即使在内部循环中,现代CPU通常在同一时间执行这种竞争性的代码序列时钟周期数!单一通用实现通常都很好。"

或者正如Donald Knuth所说,“过早优化是问题的根源万恶之中。“(《计算调查》,第6卷,第4期,第268页)。

虽然宏的坏处众所周知,但仍有一些宏是首选解决方案的情况:

  • 通过#include防止多次包含标头警卫。
  • 从传递次要配置信息配置头到其他文件。

适当:对于较小的编译时间否则成本高昂或令人困惑的变化安装、使用或维护。更适合沟通在库组件内部和之间进行通信图书馆用户。

不合适:如果其他技术可以这样做。

要最小化宏的负面影响:

  • 仅当宏明显优于其他宏时才使用宏技术。他们应该被视为最后的手段。
  • 名称应全部大写,并以命名空间名称。这将使得名的可能性降到最低碰撞。例如,#include guard用于增强名为foobar.h的头可能被命名为BOOST_foobar_h。

单独的文件

库组件可以有多个变体,每个变体包含在其单独的文件中。的文件将最合适的变体复制到合适的安装时包含或实现目录。

在boost库中提供这种方法的方法是将专用实现作为单独的文件包含在中的独立子目录。ZIP分发文件。对于中的结构。ZIP分发文件名为foobar的库,它既有默认的也有专用的变体可能类似于:

foobar.h//默认头文件foobar.cpp//默认实现文件readme.txt//自述文件解释了何时使用哪些文件self_contained/foobar.h//头中所有内容的变体linux/foobar.cpp//替换默认值的实现文件win32/foobar.h//替换默认值的头文件win32/foobar.cpp//替换默认值的实现文件

适当的:当不同平台需要不同的实现,或者可能实现之间的性能差异。

不合适:当使用有意义时在同一安装中有更多的变化。

单独的组件

而不是具有单个组件,提供几个单独的组件。对于例如,Boost库当前提供作用域_ptr共享ptr而不是一个智能打印机类参数化来区分这两种情况。有几种方法可以选择组件:

  • 在编码期间由程序员硬连线。
  • 由程序员编写的运行时逻辑选择(权衡一些额外的空间、时间和程序复杂性能够在运行时选择实现。)

适当的:变化会出现分歧,当合理使用超过其中一个变体。当运行时选择需要实现。

不合适:当变化是可以是通过使组件成为模板来更好地处理。也不是当变体的选择最好由某些设置完成时或程序本身之外的安装机制。因此通常不适合处理平台差异。

注:有一种相关的技术,其中接口被指定为抽象(纯虚拟)基础类(或接口定义语言),以及实现选择被传递给一些第三方,例如作为动态链接库或对象请求代理。尽管如此是一种强大的技术,它远远超出了这一范围讨论。

基于模板的方法

将类或函数转换为模板通常是应对变化的优雅方式。基于模板的方法提供最佳的空间和时间效率,以换取将实现选择限制为编译时间。

重要的模板技术包括:

  • 数据类型参数化。这允许单个组件来操作各种数据类型,这是为什么模板最初是发明的。
  • 特征参数化。如果参数化很复杂,将方面绑定到单个特性帮助器类中可以允许在隐藏混乱细节的同时进行巨大的变化。C类++标准库提供了这种习惯用法的几个示例,例如迭代器数组(24.3.1lib.iterator.ttraits)和字符图<>(21.2lib.char.tracts)。
  • 专业化。模板参数可以纯粹使用为了选择专业。对于例子:
SomeClass<fast>my_fast_object;//fast和small是空类SomeClass<small>my_small_object;//仅用于选择专业化

适当的:当需要变更时由于数据类型或特征或与绩效相关在几种算法中进行选择,以及程序何时可以合理使用多个变体。

不合适:变化是不同的,或者当变化的选择是最好的由程序本身之外的某种机制完成。因此通常不适合处理平台差异。