现在的位置: 首页 > 综合 > 正文

Boost笔记

2011年11月24日 ⁄ 综合 ⁄ 共 8314字 ⁄ 字号 评论关闭

如下是阅读“Boost程序库完全开发指南-深入C++“准”标准库”的大纲学习摘要

一、 Boost命名规则33

Boost库在VC编译器下支持库自动链接技术(使用#pragma comment (lib,xxx)),只

要把所有生成的lib拷贝到vc的搜索路径下,不需要你费心,编译器会自动根据编译选项找到

合适的库链接成可执行文件。

但如果读者使用的是GCC、XLC或者其他不支持自动链接技术的编译器,就有必要了解Boost库的命名规则,以便在链接时指定正确的库。

libboost_file system-vc8 0 -mt-sgdp-1_4 2 . lib

前缀:统一为lib,但在Windows下只有静态库有lib前缀;

库名称:以"boost一”开头的库名称,在这里是boost_filesystem;

编译器标识:编译该库文件的编译器名称和版本,在这里是-vc80;

多线程标识:支持多线程使用-mt,没有表示不支持多线程;

ABI标识:这个标识比较复杂,标识了Boost库的几个编译链接选项;

n s:静态库标识

n gd: debug版标识

n p:使用STlport而不是编译器自带STL实现

版本号:Boost库的版本号,小数点用下画线代替,在这里是1 42;

扩展名:在Windows上是.lib,在Linux等类Unix操作系统上是.a或者.so。

在链接Boost程序库时可以有两种方式,一种是在编译命令行直接指明库文件全路径,另一种是用-L指定库文件所在路径,再用-l指定库文件名。

嵌入自己的工程编译

编译库的方法使用Boost费时费力,有时还要面临链接的烦恼。本书推荐使用作者自行实践的另一种方式:把Boost源代码嵌入到自己的工程中编译。

这种方法的原埋类似vc的预编译技术(灵感来源于著名的StdAfx.h),在工程中直接包含Boost库的cpp文件(大部分都很小很少),不但可以省略库的编译步骤,而且源代码还获得了独立于编译器、操作系统和Boost库版本的好处(任何一个因素发生变化时都不需要换编译器重新编译库),能够增强程序的可移植性。

不过这种方法也有小小的代价,就是每个工程都要重新编译Boost库,不如前两种方式那样可以(暂时的)“一劳永逸”,但作者认为其平台无关的优点还是大于缺点。在其后的章节里会向读者示范这种嵌入工程编译的方式如何具体实现,这里暂举一个小例子:

///sysprebuild.cpp -个嵌入编译源代码文件

#define BOOST_SYSTEM_NO_LIB

#include <libs/system/src/error_code. cpp>

//禁用Boost的自动链接功能

//包含嵌入编译源代码

以上代码实现了boost.system库的嵌入编译,读者只需要将该文件(sysprebuild. cpp)

二、 时间日期

1. 概述

78

timer库的实现原理很简单,可能很多读者都曾经编写过类似的代码。但即使是这样小而

简单的库也包含了深刻的设计理念。基于跨平台可移植的指导思想,timer使用了c标准中的std::clock(),而没有使用操作系统可能提供的更精确的计时函数,std::clock()也更加

可靠。

timer和progress—timer是用于计时的小工具,精度不高但好用够用,特别是progress

timer.它利用了c++中析构函数会被自动调用的特点能够自动显示时间,用起来更方便。

progress_display是一个可以显示程序执行进度的工具,,在很耗时的应用程序中可以给

出友好的进度提示,使用也很容易。但它使用的是字符界面,不够好看,而且很容易被程序的其他输出打乱显示。使用它时我们必须保证自己的程序不能有任何可能的输出,否则

progress_display就完全失去了意义。

Progress_timer和progress_display还有一个有趣的特点是它们都私有继承了noncopyable类,防止被无意的拷贝而破坏了正确的行为。noncopyable是Boost库的一个实用工具类,我们很快就会在4.1小节(95页)看到它的详细用法。

时间与日期处理是生活中的常见问题,但C++98标准中并没有制定这方面的规范,date_time库填补了这个空白,提供了基于格里高利历的日期时间处理,功能非常全面。它支持时间点、时间长度和时间区间等基本概念,提供了从年月日到时分秒、微秒乃至纳秒等许多级别的时间分辨率,还重载了许多操作符,可以进行比较、加减等运算,能够满足绝大多数程序对时间处理的要求。

2. Timer库37 40 43
使用

timer库包含三个组件,分别是:计时器类timer、progress timer和进度指示类progress_display

timer位于名字空间boost,为了使用timer组件,需要包含头文件<boost/timer.hpp>,即:

#include <boost/timer.hpp>

using namespace boost;

3. date_time库 48

bjam --toolset=msvc --with-date—time -build-type=complete stdlib=stlport stage

编译后会生成形如liblooost_date_time-vc80-mt-sgdp-l_42 .lib的静态库或者动态库。

如不想使用bjam预编译库,可以直接在工程内包含date time库的实现cpp源文件,使

用嵌入工程编译的方式。cpp源代码如下:

///dateprebuild.cpp

#define BOOST—DATE__ TIME—SOURCE

#include <libs /date_time/s rc/gregorian/greg_names. hpp>

#include <libs/date_time/src/gregorian/date_generators. cpp>

#include <libs/date_time/src/gregorian/greg_month.cpp>

#include <libs /date_time/src/gregorian /greg_weekday. cpp>

#include <libs /date_time/src/gregorian/gregorian_types. cpp>

茌工程的其他源代码使用date time库时,需要在包含头文件之前定义宏BOOST_DATE_TIME_SOURCE BOOST_DATE_TIME_NO_LIB或者BOOST_ALL_NO_LIB:

#defineOOST_DATE_TIME_SOURCE

#include <boost/date _time/gregorian/gregorian. hpp>

三、 内存管理

概述

113

内存管理是c++程序开发中永恒的话题,因为没有垃圾回收机制,小心谨慎地管理内存等系统资源是每一个c++程序员都必须面对的问题。C++98标准提供了auto_ptr,可以自动释放资源,但没有解决所有问题。本章讨论了Boost关于内存管理的两个库:smart_ptr和pool,并对smart_ptr倾注了大量的篇幅。

boost.smart_ptr库提供了数种新型智能指针,弥补了std::auto_ptr的不足,可以有

效地消除new和delete的显示使用,减少甚至杜绝代码资源泄漏。

scoped_ptr是smart ptr库中最容易学习和使用的一个,它的行为类似auto_ptr,但所有权更明确,清晰地表明了这种智能指针只能在声明的作用域中使用,不能转让,任何对它的复制企图都会失败。这个特点对代码的后期维护工作非常有用。

shared_ptr可能是最有用的智能指针,也是这些智能指针中最“智能”的一个,不仅可以管理内存,也可以管理其他系统资源,能够应用于许多场合。它可以自动地计算指针的引用计数,其行为最接近原始指针。几乎可以在任何可以使用原始指针的地方使用shared ptr,并且不用承担资源泄漏的风险。shared__ ptr不仅可以保存指针,通过配置删除器也可以自动释放指针关联的资源。在基本的用法之外,我们还讨论了shared- ptr的很多其他用法,如实现pimpl惯用法、应用于工厂模式、持有任意对象的指针等,这些用法进一步展示了它的强大功能。为了方便shared ptr的使用,smart_ptr库还提供了工厂函数make shared(),进一步消除了代码中new操作符的使用。

scoped_array和shared_array是scoped_ptr和shared ptr对动态数组的扩展,它们为动态数组提供了可自动删除的代理,shared_array比scoped_array育更多的用途。但我们更应该使用vector和shared ptr<vector<>>,除非程序对性能有非常苛刻的要求。

章还简要讨论了smart_ptr的另两个组件:weak_ptr能够“静态”地观察shared_ptr而不影响引用计数,intrusive_ptr则为实现侵入式智能指针提供了技术方案。

pool库是Boost程序库在内存管理方面提供的另一个有用工具,它实现了高效的内存池,用于管理内存资源。pool库提供了pool、object_pool、singleton pool和pool alloc四种形式的内存池,适合于各种情形的应用。可以完全把它们当做是一个小型的垃圾回收机制,在内存池中随意地动态创建对象,而完全不用关心它的回收,也不用对原有类做任何形式的修改。pool库的四个内存池类中前三个都很有用,尤其是object_pool,它可以统一地管理各种对象的创建与销毁,能够很好地应用在各种规模的面向对象软件系统中。至于pool_alloc,它是符合c++标准的一个内存分配器实现,快速且高效,但通常STL自带的内存分配器会更好地与容器配合工作,使用pool_alloc咐需要仔细地评估可能带来的影响。

pool库还提供一个底层的实现类simple_segregated_storage,它实现了简单分隔存

储的管理机制,是pool库其他类的基础。它不适合大多数库用户,但可以作为自行实现内存池类的一个很好的起点。

smart_ptr库

83 87 89

这些智能指针都位于名字空间boost,为了使用smart_ptr组件,需要包含头文件

<boost/smart_ptr.hpp>.即:

#include <boost/smart_ptr. hpp>

using namespace boost;

scoped_ptr

scoped_ptr是一个很类似auto_ptr的智能指针,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确地删除。但scoped__ ptr的所有权更加严格,不能转让,一旦scoped_ptr获取了对象的管理权,你就无法再从它那里取回来。scoped_ptr拥有一个很好的名字,它向代码的阅读者传递了明确的信息:这个智能指针只能在本作用域里使用,不希望被转让。

shared_ptr

shared_ptr是一个最像指针的“智能指针”,是boost.smart_ptr库中最有价值、最重要的组成部分,也是最有用的,Boost库的许多组件——甚至还包括其他一些领域的智能指针都使用了shared_ptr。抱歉,我实在想不出什么更恰当的词汇来形容它在软件开发中的重要性。再强调一遍,shared_ptr非常有价值、非常重要、非常有用。shared ptr与scoped ptr -样包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针o,可以被自由地拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0)它时才删除被包装的动态分配的对象。shared_ptr也可以安全地放到标准容器中.

pool库

105

四、 实用工具 180

noncopyable

115

noncopyable允许程序轻松地实现一个禁止复制的类。noncopyable位于名字空间boost,为了使用noncopyable组件,需耍包含头文件<boost/noncopyable.hpp>或者<boost/utility.hpp>,后者包含了数个小工具的实现:

#include <boost/noncopyable . hpp>

assign

126

许多情况下我们都需要为容器初始化或者赋值,填入大量的数据,比如初始错误代码和错误信息,或者是一些测试用的数据。STL容器仅提供了容纳这些数据的方法,但填充的步骤却是相当地麻烦,必须重复调用insert()或者push back()等成员函数,这正是boost. assign出现的理由。

assign库重载了赋值操作符operator+=、逗号操作符operator,和括号操作符operator(),可以用难以想象的简洁语法非常方便地对STL容器赋值或者初贻化。在需要填入大量初值的地方很有用。

assign库位于名字空间boost::assign,为了使用assign库,需要包含头文件

<boost/assign.hpp>,它包含了大部分assign库的工具,即:

#include <boost/assign . hpp>

using namespace boost : : assign;

4.4.1 使用操作符+=向容器增加元素

boost.as sign的用法非常简单,由于重载了操作符+=和逗号,可以用简洁到令人震惊的语法完成原来用许多代码才能完成的工作,如果不熟悉c++操作符重载的原理你甚至都不会意识到在简洁语法下的复杂工作。

使用assign库时必须使用using指示符,只有这样才能让重载的+=,等操作符在作用域内生效。例如:

#include <boost/assign. hpp>

单件

137

位于不同的命名空间的两个实现单例类

uuid

166

utility

177

五、 字符串和文本处理

lexical_cast

184

Format

187

168

boost.format库“扬弃”了printf,实现了类似于printf()的格式化对象,可以把参

数格式化到一个字符串,而且是完全类型安全的。

format组件位于名字空间boost,为了使用format组件,需要包含头文件

<boost/format .hpp>,即:

#include <boost/format*hpp>

using namespace boost;

5.2.1简单的例子

我们先通过一个简单的例子来了解format,看看它与printf()有什么相似和不同:

#include <boost/format .hpp>

using namespace boost;

int main ()

{

cout《 format ( " ooS : ood+ood=%d\n") oo "sum" % 1 00 2 00 (1+2) ;

format fmt(”(%100+002 00) ★00200=%3%\n")j

fmt%2005 j

fmtoo ((2+5) *5);

cout<<fmt.str();

)

程序运行结果如下:

sum:1+2=3

(2+5) ★5= 35

string_algo

195

232

六、 防御性编程

BOOT.ASSERT

234

七、 容器和数据结构

概述

345

259

八、 算法

概述

356

foreach

348

九、 操作系统相关

概述

391 438

system

394

filesystem

400

十、 函数与回调

概述

485

439

bind

449

function

457

signals2

465

十一、 并发

thread

487

asio

513

IPC interprocess

十二、 转换

Conversion 库由四个转换函数组成,分别提供了更好的类型安全性(polymorphic_cast), 更高效的类型安全防护(polymorphic_downcast), 范围检查的数字转换(numeric_cast), 以及文字转换(lexical_cast)。这些类cast函数共享C++转型操作符的语义。与C++的转型操作符一样,这些函数具有一个重要的品质,类型安全性,这是它们与C风格转型的区别:它们明确无误地表达了程序员的意图[2]。我们所写的代码的重要性不仅在于它可以正确执行。更重要的是代码可否清晰地表达我们的意图。这个库使得我们可以更容易地扩展我们的C++词汇表。

polymorphic_cast

头文件: "boost/cast.hpp"

必须记住,其它人将要维护我们写的代码。这意味着我们必须确保代码以及它的意图是清晰并且易懂的。这一点可以通过注释部分地解决,但对于任何人,更容易的方法是不需加以说明的代码。当(指针)转型失败被认为是异常时,polymorphic_castdynamic_cast更能清晰地表明代码的意图,它也导致更短的代码。如果转型失败不应被认为是错误,则应该使用dynamic_cast,这使得dynamic_cast的使用更为清楚。仅仅使用 dynamic_cast 来表明两种不同的意图很容易出错,而不够清楚。抛出异常与不抛出异常这两个不同的版本对于大多数程序员而言太微妙了。

何时使用 polymorphic_castdynamic_cast:

· 当一个多态转型的失败是预期的时候,使用 dynamic_cast<T*>. 它清楚地表明转型失败不是一种错误。

· 当一个多态转型必须成功以确保逻辑的正确性时,使用 polymorphic_cast<T*>. 它清楚地表明转型失败是一种错误。

· 对引用类型执行多态转型时,使用 dynamic_cast.

polymorphic_downcast

头文件: "boost/cast.hpp"

使用static_cast进行向下转换通常是危险的。你不应该这样做,但如果一定要,使用polymorphic_downcast可以增加一点安全性。它在调试模式下增加了测试,可以帮助你发现转型的错误,但你必须测试所有可能的转型以确保它的安全使用。

· 如果你正在使用向下转型并需要在发布版本中获得static_cast的速度,就用 polymorphic_downcast; 至少在测试时你可以在出错时得到断言的帮助。

· 如果不能测试所有可能的转型,就不要使用 polymorphic_downcast.

记住这是一种优化方法,你应该在确定需要它们时才使用。

numeric_cast

头文件: "boost/cast.hpp"

numeric_cast 提供了算术类型间高效的范围检查转换。在目标类型可以持有所有源类型的值时,使用 numeric_cast没有额外的效率代价。它只在目标类型仅能表示源类型的值的子集时有影响。当转换失败时,numeric_cast 通过抛出一个 bad_numeric_cast异常来表示失败。对于数值类型间的转换有很多复杂的规则,确保转换的正确性是很重要的。

以下情况时使用 numeric_cast:

· 在无符号与有符号类型间进行赋值或比较时

· 在不同大小的整数类型间进行赋值或比较时

· 从一个函数返回类型向一个数值变量赋值,为了预防该函数未来的变化

在这里注意到一个模式了吗?模仿已有的语言和库的名字及行为是简化学习及使用的好方法,但也需要仔细地考虑。增加内建的C++转型就象沿着狭窄的小路行走;一旦迷路会带来很高的代价。遵循语言的语法及语义规则才是负责任的。事实上,对于初学者,内建的转型操作符与看起来象转型操作符的函数可能并没有不同,所以如果行为错误将会导致灾难。numeric_cast 有着与 static_cast, dynamic_cast, 和 reinterpret_cast类似的语法和语义。如果它看起来和用起来象转型操作,它就是转型操作,是对转型操作的一个良好的扩展。

lexical_cast
头文件: "boost/lexical_cast.hpp"

lexical_cast 是用于字符串与其它类型之间的字面转换的一个可重用及高效的工具。它是功能性和优雅性的结合,是杰出程序员的伟大杰作[16]。不要在需要时实现小的转换函数,更不要在其它函数中直接插入相关逻辑,应该使用象lexical_cast 这样的泛型工具。它有助于使代码更清晰,并让程序员专注于解决手上的问题。

[16] 我知道,我总是很傲慢的,我们这些程序员,工作中常常需要数学、物理学、工程学、建筑学,和其它一些艺术和学科。这会使人畏缩,但也有无穷的回报。

以下情况时使用lexical_cast:

· 从字符串类型到数值类型的转换

· 从数值类型到字符串类型的转换

· 你的自定义类型所支持的所有字面转换

抱歉!评论已关闭.