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
相關文章
相關標籤/搜索