Boost入门

                                                【转载网友转载的  不过不知道原做者地址】

Boost入门向导
 
简介:
boost是一套开源的、高度可移植的C++模板库。它由C++标准委员发起,且里面不少组件有望成为下一代的C++标准库,其地位将会与STL同样。
boost库的英文站点是http://www.boost.org。
若是上个页面不能访问,能够看http://boost.c-view.org,它是Boost镜像。
boost按功能分为:字符串、容器、算法、迭代器、数据结构、内存管理、多线程、IO等。其中字符串组中的正规表达式能够与POSIX API和Perl语言处理正则表达式的功能相媲美;多线程组件不比java的多线程难用;内存管理组件若是能合理使用能够杜绝内存泄露,而其效率更是与垃圾收集机制不可同日而语。
boost的接口(或concept)彻底与STL兼容,它在实现上使用了不少STL功能,它自己的组件也能够做为STL容器及算法的元素,因此有使用上,感受不出是两个类库,咱们能够当成是一个类库来使用就好了。只是boost库是在boost::名字空间里。
而我我的最喜欢的一点是,boost的源码可读性很是高,非不得已它不多用宏,且不会象某些STL的实现同样,处处都是下划线开头的变量。

下载与安装:
当boost成为标准库后,如下步骤就能够省略了,如今要用boost,还得亲自动手。
下载:
打开boost主页,点击Getting StartedàDownloadàdownload releases from SourceForge,目前最新版本是boost_1_31_0.tar.bz2。而后再在同一个页面中下载boost-1.31.0-regex-patch-20040503.zip,这是一个补丁。
下载以后,X/boost_1_31_0/ index.htm是一个本地的文档目录。
安装:
大多数boost组件只要直接包含相应头文件就可使用[1]。但若是你用到date_time、filesystem、graph、python、regex、signals、test、thread 等组件,则要要编译成相应的静态或动态库。
新版本的boost在全部平台下统一使用jam完成编译与部署,而且boost还特别特化了一个jam版本bjam。这里以1.31.0版本为例,编译全部的boost库:
执行boost源码发布包中的X/boost_1_31_0/tools/build/jam_src下的build.bat,build.bat将自动在系统中选择一个编译器,并在bin.xxxx目录下生成jam,bjam等工具。
生成bjam后,配置好命令行编译环境。并用bjam解释(boostsrc)/下的jam文件便可编译并部署。其参数繁多,这里不一一列出,见X/boost_1_31_0/boost_1_31_0/more/getting_started.html #Build_Install。
String and text processing:
提供了字符串的操做功能,大概分为五个组件。但要注意的是,某些组件效率上可能会有问题,好比字符串与基本类型的相互转换、格式化等,它们的实现是先把输入参数转化为STL的字符流,而后经过字符流转换为用户想要的类型输出(从这一点也能够看出,能够相互转换的类型只限于字符流可接受的那几类,字符流使用与可接受类型与io流基本同样)。
组件 描述
lexical_cast 字符串与其它类型的相互转换
format 格式化字符
regex 正则表达式
spirit 字符串分析框架。用inline的C++写成的EBNF语法。
tokenizer 按位移或字符提取字符串
lexical_cast:
不少时候,咱们想要把字符串与其它类型相互转换,而使用标签的C库,好比atoi,itoa等有时会很麻烦,并且难以记住全部这些函数,使用lexical_cast作这种事情则很是之简单而安全。例子以下:
#include <boost/lexical_cast.hpp>

void test_lexical_cast()
{
std::string strNember = boost::lexical_cast<std::string>(123);
int a = boost::lexical_cast<int>("123");
double b = boost::lexical_cast<double>("123.456");
}

要注意的是,test_lexical_cast里的最后两句在VC6.0下不能经过编译。

format:
format的使用与通常的C格式化函数要灵活的多,并且它提供了多种语言风格的格式化。format实际上是一个仿函数,查看源代码有如下的定义:
typedef basic_format<char > format;
format要真正格式化的参数是经过operator%来传递给函数对象的。下面是一个简单的例子:
#include <boost/format.hpp>
std::cout <<
boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50;

format生成的对象能够直接入到输出流,要生成一个字符串,咱们能够这样:
std::string str = boost::lexical_cast<std::string>(
boost::format("%1% %2% %3% %2% %1% /n") % "a" % "b" % "c"
);
这里生成的字符串是:"abcba /n"(%1%对应的参数是字符a,%2%对应的参数是字符b,%3%对应的参数是字符c)。
regex:
要分析一个字符串是否符合某种语法规则是一件很烦人并且容易出错的事,boost::regex组件实现了这种分析功能,咱们就不用本身去分析了。
语法分析一般使用正则表达式,regex正是经过接受一个正则表达式字符串做为参数,来分析给定的字符串是否符合某种语法规则的。
下面这个例子字符串"abcd"是否符合表达式 /d{4}[- ]){3}/d{4}:
#include<boost/regex.hpp>
std::string s("abcd");
static const boost::regex e("(//d{4}[- ]){3}//d{4}");
if(boost::regex_match(s, e))
std::cout << "match /n";
else
std::cout << "not match /n";

咱们还能够分析一篇文档,提取只符合表达式的内容,好比,有一篇xml文档,超级连接的地址是放在属性href中,我想要提取全部超连接的地址能够这样写表达式:
boost::regex expression("//s+href//s*=//s*/"([^/"]*)/"");
完整的代码以下:
void test_regex_split()
{
using namespace boost;
regex expression("//s+href//s*=//s*/"([^/"]*)/"");
// 假如文档的内容以下:
std::string s = "<a href=/"index.html/"><img src=/"logo.gif/"></a>";
std::vector<std::string> result; // 用于保存结果
// 把字符串s按表达式expression分割,并把结果放到result中
regex_split(std::back_inserter(result), s, expression);
for (std::vector<std::string>::iterator it = result.begin(); it != result.end(); ++it)
std::cout << *it;
std::cout << std::endl;
}

注意,要用regex是须要编译成相应的库的。
tokenizer:
tokenizer组件提供了一种很是弹性且容易使用的方法来分割字符串。它的使用比较简单,下面两个例子,例子一是把"hello, word!"分红7+5两个字符,例子二是把字符串按分隔符符分隔开:
#include <boost/tokenizer.hpp>
void test_tokenizer1()
{
std::string s = "hello, word!";

int offsets[] = {7, 5};// 分红两串,一串7个字符,一串5个
boost::offset_separator f(offsets, offsets+2);

typedef boost::tokenizer<boost::offset_separator> SeparatoTokenizer;
SeparatoTokenizer tok(s, f);
for(SeparatoTokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
{
std::cout << "<" << *it << "> " << '/t';
}
std::cout << std::endl;


void test_tokenizer2()
{
std::string str = ";;Hello|world||-foo--bar;yow;baz|";
boost::char_separator<char> sep("-;|"); //分隔符

typedef boost::tokenizer<boost::char_separator<char> > CharTokenizer;
CharTokenizer tokens(str, sep);
for (CharTokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter)
{
std::cout << "<" << *tok_iter << "> " << '/t';
}
std::cout << std::endl;
}

Containers:
boost中的容器主要是做为STL容器的一个补充。静态数组、多维数组的使用跟通常的C语法数组差很少,但做为容器,它提供了STL中的不少concept(好比iterater),因此可使用STL算法来访问它们。dynamic_bitset 是一种动态的biset。property map是把key对象影射到value对象,全部具备下标操做的类型均可以做为它的元素,对property map的需求来源于BGL。
组件 描述
array 符合STL容器语意4的静态数组
multi_array 多维数组,并且能够与array适配(前提是有共同的边界)
dynamic_bitset 一种能够在运行时改变大小的bitset。
property map 一套能够把key对象影射到value对象的类与全局函数
graph 图容器,即BGL[2]

array:
STL提供了一套接口(或concept),用于处理不一样容器的算法。但普通数组却由于没有相应的接口[3]而不能很好的配合这些算法的使用。
boost中的array具备静态数组的效率与功能,且提供了STL容器的各类接口。

multi_array:
使用STL,若是要声明一个二元的整数数组,咱们能够这样:
std::vector<std::vector<int>>
若是要三维,四维,N维,还使用这种方式?先不说这种代码有多恶心,作起来有多麻烦,只要能完成工做就好了,但不少时候恰恰不能,好比在效率上有要求的时候(想想vector的实现,这种动态增长若是发生在N维数组上)。而使用普通的数组,又不能很好配合STL算法,这在上面已经提过了。
而boost的multi_array组件提供了标准库的接口,并且功能与效率上与普通数组同样。下面是一个该组件的简单例子:
#include "boost/multi_array.hpp"

void test_array ()
{
// 建立一个 3 x 4 x 2 的3D数组
boost::multi_array<double, 3> A(boost::extents[3][4][2]);

typedef boost::multi_array<double, 3>::index index;

// 给数组的元素赋值
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;

// 输出数组的元素值
for(i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
std::cout << A[i][j][k] << "/t";

std::cout << std::endl;
}

dynamic_bitset:
boost的dynamic_bitset几乎等价于std::bitest,不一样的是,dynamic_bitset的大小是能够在运行时改变的。该组件在使用VC6.0下编译不过。

property map:
property map定义了一套接口把key对象影射到相应的value对象,全部具备下标操做的类型(好比指针、数组、std::map等)均可以做为它的元素。对property map的需求最初来源于BGL。
property map的接口包含三个全局函数get(), put(), 和 operator[]。
下面是property map的使用例子,例子中使用到了boost::associative_property_map类,但其实使用其它的具备下标操做的类型也同样能够:
#include <boost/property_map.hpp>
template <typename AddressMap>
void foo(AddressMap address)
{
typedef typename boost::property_traits<AddressMap>::value_type value_type;
typedef typename boost::property_traits<AddressMap>::key_type key_type;

value_type old_address, new_address;
key_type fred = "Fred";
old_address = boost::get(address, fred);
new_address = "384 Fitzpatrick Street";
boost::put(address, fred, new_address);
address["Joe"] = "325 Cushing Avenue";
}

void test_property_map()
{
typedef std::map<std::string, std::string> NameAddrMap;
NameAddrMap name2address;
boost::associative_property_map<NameAddrMap> address_map(name2address);
name2address.insert(std::make_pair(std::string("Fred"),
std::string("710 West 13th Street")));
name2address.insert(std::make_pair(std::string("Joe"),
std::string("710 West 13th Street")));

foo(address_map);
for (NameAddrMap::iterator it = name2address.begin(); it != name2address.end(); ++it)
std::cout << it->first << ": " << it->second << "/n";
}

Data structures:
组件 描述
any 能够接受不一样的类型的值,当一个容器要接受不一样的类型元素时用它会很方便
compressed_pair
与std::pair类似,但若是其中一个元素为空类时,会比std::pair更节省空间
tuple
能够定义一个或多个元素的结构,做为函数返回值时会很方便
tuple:
若是说,pair是能够定义有两个元素的结构体,那么tuple是能够定义1到10元素的结构体。tuple的大部分定义是在boost::tuples::名字空间内(除了某些很通用的是在boost::内)
访问tuple元素能够经过两个方式,
t.get<N>()
或者
get<N>(t)
这里,t是一个tuple实例。(第一种方法在VC6.0下编译不过)

它的使用例子以下:
#include "boost/tuple/tuple.hpp"
void test_tuple()
{
// 最多能够10元素
boost::tuples::tuple<char, double, std::string> triples('a', 2.4, "hello");
std::cout << boost::tuples::get<0>(triples) << '/t'
<< boost::tuples::get<1>(triples) << '/t'
<< boost::tuples::get<2>(triples) << std::endl;
}

Memory:
Memory中的组件比较通用,pool组件提供的内存分配可使指针为做一个真正的原生指针,而又不用管理内存。智能指针要比std::auto_prt的好,但并不是不能够代替(以前网上有编文章评论没有loki提供智能指针的好用,并且KFC也有相应的组件。)
组件 描述
pool 内存池管理
smart_ptr 智能指针,总共提供了6种类型

pool:
pool是什么?
pool是一套很是高效的内存分配方案。
为何要使用pool?
使用pool分配内存获得的指针是真正的指针,这意味着,使用者能够对内存有更多的控制(相对于智能指针)。使用pool接口,你能够选择只运行对象的析构函数或只简单地对指向对象的指针回收。pool会保证没有内存泄漏。
何时使用pool?
当有大量小对象分配与回收,而又不想去亲自去管理内存时。

总之,当你想要高效率的方式去操纵内存时用它会带来不少好处。

pool 提供了四个比较一般的组件:pool、object_pool、singleton_pool、pool_alloc。
下面给出前两个组件的简单使用样例:
#include <boost/pool/pool.hpp>
void test_pool_BaseType()
{
boost::pool<> p(sizeof(int));
for (int i = 0; i < 5; ++i)
{
int* const t = (int*)p.malloc();
*t = i;
std::cout << *t << '/t';
}
std::cout << std::endl;
}// on function exit, p is destroyed, and all malloc()'ed ints are implicitly freed

#include <boost/pool/object_pool.hpp>
class X {};
void test_pool_object()
{
boost::object_pool<X> p;
for (int i = 0; i < 10000; ++i)
{
X* const t = p.construct();
// to do
}
}

使用pool,咱们能够不用管内存释放。固然,若是你想本身释放内存,可使用void destroy(element_type * p)成员函数。这里element_type是传进来的模板参数类型。
object_pool是使用内存池管理内存,若是频繁分配和删除相同类型的对象,object_pool要比直接调用new,delete高出几个数量级。
smart_ptr:
STL的std::auto被不少人认为是标准库的一个缺陷,其实并非这样,只是由于std::auto提供的功能不够丰富摆了,它缺乏对引用数和数组的支持,而且,std::auto_ptr在被复制的时候会传输全部权。由于缺乏引用,因此对象没有共享全部权,结果就不能够跟其它STL组件(好比容器)很好的配合使用。
boost提供的智能指针正好补充了以上功能,比较通用的组件有:
scoped_ptr,用于处理单个对象的惟一全部权。
scoped_array,与scoped_ptr相似,可是用来处理数组的。
shared_ptr,容许共享对象全部权。
shared_array,容许共享数组全部权。

其它:
date_time:
一套处理日期与时间的组件,在它以前,我没有发现有相似的C++库,每次处理时间日期时,都觉繁琐且容易出错,如今用它,就不再用记浮点数0是哪年哪月哪日了。使用date_time要编译boost代码成相应的库。它的使用比较简单,下面给出例子:
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

void test_data_time()
{
using namespace boost::gregorian;

date today = day_clock::local_day();
std::string strToday = to_simple_string(today);
std::cout << "today is: " << strToday << std::endl;

using namespace boost::posix_time;

date d(2004, May, 1);
ptime t1(d, hours(5)+minutes(4)+seconds(2)+millisec(1));
ptime t2 = t1 - hours(5) - minutes(4) - seconds(2) - millisec(1);
time_duration td = t2 - t1;

std::cout << to_simple_string(t2) << " - "
<< to_simple_string(t1) << " = "
<< to_simple_string(td) << std::endl;
}
[1] 这里是大多数而不是所有,是由于boost不象STL那样已经标准化,主流的编译器要么提供本地版本要么彻底支持开源版本。而目前boost的开源版本可能不是每个编译器都能彻底支持;另外一个与STL不一样的是,boost某些库须要编译成相应的静态库与动态库才能够用。
[2] Boost Graph Library(boost 图形库,一套用于图形的容器与算法组件)
[3] 其实普通数组的指针也是能够看做为一种简单的iterator
相关文章
相关标签/搜索