boost庫學習筆記

pamxy發表於2013-06-04

轉自:http://www.cnblogs.com/BloodAndBone/archive/2011/02/28/1967116.html

1.Boost C++ 庫概述

Boost C++ 庫 是一組基於C++標準的現代庫。 其原始碼按 Boost Software License 來發布,允許任何人自由地使用、修改和分發。 這些庫是平臺獨立的,且支援大多數知名和不那麼知名的編譯器。
Boost 社群負責開發和釋出 Boost C++ 庫。 社群由一個很大的C++開發人員群組組成,這些開發人員來自於全球,他們通過網站 www.boost.org 以及幾個郵件列表相互協調。 社群的使命是開發和收集高質量的庫,作為C++標準的補充。 那些被證實有價值且對於C++應用開發非常重要的庫,將會有很大機會在某天被納入C++標準中。
Boost 社群在1998年左右出現,當時剛剛釋出了C++標準的第一個版本。 從那時起,社群就不斷地擴大,現在已成為C++標準化工作中的一個重要角色。 雖然 Boost 社群與標準化委員會之間沒有直接的關係,但有部分開發者同時活躍於兩方。 下一個版本的C++標準很大可能在2011年通過,其中將擴充套件一批庫,這些庫均起源於 Boost 社群。
要增強C++專案的生產力,除了C++標準以外,Boost C++ 庫是一個不錯的選擇。 由於當前版本的C++標準在2003年修訂之後,C++又有了新的發展,所以 Boost C++ 庫提供了許多新的特性。 由於有了 Boost C++ 庫,我們無需等待下一個版本的C++標準,就可以立即享用C++演化中取得的最新進展。
Boost C++ 庫具有良好的聲譽,這基於它們的使用已被證實是非常有價值的。 在面試中詢問關於 Boost C++ 庫的知識是常見的,因為知道這些庫的開發人員通常也清楚C++的最新創新,並且能夠編寫和理解現代的C++程式碼。

2.Boost常用庫介紹

關於Boost庫怎樣安裝,我這裡不多講,網上資料很多。我這裡重點介紹一下boost的幾個庫,以便在我們以後的開發中提高工作效率。Boost庫檔案採用的.hpp的字尾,而不是分成兩個檔案,也就是”.h+.cpp”,之所以這樣做是有理由的,首先就是與普通的C/C++標頭檔案區分,另外一個原因就是使Boost庫不需要預先編譯,直接引用程式設計師的工程即可編譯連結,方便了庫的使用。最後一個(無奈的)原因就是C++編譯器的限制,許多編譯器尚不支援C++標準提出的模板的分離編譯模式,而Boost使用了大量的模板。Boost中90%的庫不需要編譯,但像data_time、regex、test、thread等庫必須編譯成靜態庫或者動態庫。好了,言歸正傳,下面我們來開始學習boost庫吧。

2.1日期和時間處理

timer:包含三個主件,分別是:計時器類timer、progress_timer和進度條指示類progress_display。原始碼比較簡單,我們可以借鑑原始碼處理時間和進度條。在linux作業系統中timer最大隻能計時0.596523h(我們可以改寫原始碼,擴大計時時間),但是可以精確到微秒。我們在計時,進度顯示中可能會用到,下面我們給一個progress_display庫的使用示例。

#include <boost/progress.hpp>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>

int main()
{
 std::vector<std::string> v(100);
 std::ofstream fs("test");
 boost::progress_display pd(v.size());
 std::vector<std::string>::iterator pos;
 for(pos=v.begin();pos!=v.end();++pos)
 {
  fs<<*pos<<std::endl;
  ++pd;
   sleep(1);
  }
}
輸出結果:
0%   10   20   30   40   50   60   70   80   90   100% 
|----|----|----|----|----|----|----|----|----|----|  
*****

上例中實現了將一個容器的內容拷貝到一個檔案中的進度條顯示的過程。
DateTime:提供了擴充套件來處理時區的問題,且支援曆法日期和時間的格式化輸入與輸出。Boost.DateTime 只支援基於格里曆的歷法日期,這通常不成問題,因為這是最廣泛使用的歷法。 如果你與其它國家的某人有個會議,時間在2010年1月5日,你可以期望無需與對方確認這個日期是否基於格里曆。
格里曆是教皇 Gregory XIII 在1582年頒發的。 嚴格來說,Boost.DateTime 支援由1400年至9999年的歷法日期,這意味著它支援1582年以前的日期。 因此,Boost.DateTime 可用於任一曆法日期,只要該日期在轉換為格里曆後是在1400年之後。 如果需要更早的年份,就必須使用其它庫來代替。
用於處理曆法日期的類和函式位於名字空間 boost::gregorian 中,定義於 boost/date_time/gregorian/gregorian.hpp。 要建立一個日期,請使用 boost::gregorian::date 類。

#include <boost/date_time/gregorian/gregorian.hpp> 
#include <iostream> 
int main() 
{ 
  boost::gregorian::date d(2010, 1, 30); 
  std::cout << d.year() << std::endl; 
  std::cout << d.month() << std::endl; 
  std::cout << d.day() << std::endl; 
  std::cout << d.day_of_week() << std::endl; 
  std::cout << d.end_of_month() << std::endl; 
}
輸出結果: 
2010 
Jan
30 
Sat 
2010-Jan-31

2.2智慧指標

shared_ptr:是一個最像指標的“智慧指標”,它實現了引用計數型的智慧指標,可以自由的拷貝和賦值,在任意的地方共享它,當沒有程式碼使用它是才刪除被包裝的動態分配的物件。shared_ptr也可以安全的放在標準容器中,可以像使用指標以用使用shared_ptr。效能和使用指標相差無幾,卻能有效的防止記憶體洩露。

#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
class Shared
{
    public:
        Shared()
        {
            std::cout << "ctor() called"<<std::endl;
        }
        Shared(const Shared & other)
        {
            std::cout << "copy ctor() called"<<std::endl;
        }
        ~Shared()
        {
            std::cout << "dtor() called"<<std::endl;
        }
        Shared & operator = (const Shared & other)
        {
            std::cout << "operator = called"<<std::endl;
        }
};
int main()
{
    typedef boost::shared_ptr<Shared> SharedSP;
    typedef std::vector<SharedSP> VShared;
    VShared v;
    v.push_back(SharedSP(new Shared()));
    v.push_back(SharedSP(new Shared()));
}

2.3字串處理和格式化輸出

lexical_cast:lexical_cast庫進行“字面量”轉換,類似C中的atoi函式,可以進行字串、整數/浮點數之間的字面轉換。

#include <boost/lexical_cast.hpp> 
void test_lexical_cast() 
{ 
    int i = boost::lexical_cast<int>("123"); 
    cout << i << endl; 
} 

format:用於替代C裡面的sprintf,優點是型別安全,不會因為型別和引數不匹配而導致程式崩潰,而且還可以重複使用引數。

#include <boost/format.hpp> 
void test_format() 
{ 
    cout <<  
        boost::format("writing %1%,  x=%2% : %3%-th try") 
        % "toto" 
        % 40.23 
        % 50 
        <<endl; 
    format f("a=%1%,b=%2%,c=%3%,a=%1%"); 
    f % "string" % 2 % 10.0; 
    cout << f.str() << endl; 
} 

string_algo:它是一個非常全面的字串演算法庫,提供了大量的字串操作函式,如大小寫無關比較、修剪、特定模式的字串查詢等,可以在不使用正規表示式的情況下處理大多數字符串相關問題。

#include <boost/algorithm/string.hpp>
Using namespace boost;
int main()
{
string str(“readme.txt”);
if(ends_with(str,”txt”))
{
cout<<to_upper_copy(str)+”UPPER”<<endl;
assert(ends_with(str,”txt”));
}
replace_first(str,”readme”,”followme”);
cout<<str<<endl;
vector<char> v(str.begin(),str.end());
vector<char> v2=to_upper_copy(erase_first_copy(v,”txt”));
for(int i=0;i<v2.size();++i)
{
cout<<v2[i];
}
}

tokenizer:tokenizer庫是一個專門用於分詞的字串處理庫,可以用簡單易用的方法把一個字串分解成若干個單詞。它與string_algo庫的分割演算法很類似,但是有更多的變化。

#include <boost/tokenizer.hpp> 
void test_tokenizer() 
{ 
    string s("This is  , a ,test!"); 
    boost::tokenizer<> tok(s); 
    for(tokenizer<>::iterator beg=tok.begin(); beg!=tok.end();++beg) 
    { 
        cout << *beg << " "; 
    } 
} 

Xpressive:是一個先進的、靈活的、功能強大的正規表示式庫,提供了對正規表示式的全面支援,而且比原來的正規表示式庫boost.regex要好的是不需要編譯。

#include <boost/xpressive/xpressive_dynamic.hpp>
int main()
{
cregex reg=cregex::compile(“a.c”);
assert(regex_match(“abc”,reg));
assert(regex_match(“a+c”,reg));
assert(!regex_match(“ac”,reg));
assert(!regex_match(“abd”,reg));
}

2.4容器

any:是一種通用的資料型別,可以將型別包裝後統一放在容器中,最重要的是它是型別安全的。使用方法: any::type() 返回包裝的型別 any_cast可用於any到其他型別的轉化

#include <boost/any.hpp> 
void test_any() 
{ 
    typedef std::vector<boost::any> many; 
    many a; 
    a.push_back(2); 
    a.push_back(string("test")); 
    for(unsigned int i=0;i<a.size();++i) 
    { 
        cout<<a[i].type().name()<<endl; 
        try 
        { 
            int result = any_cast<int>(a[i]); 
            cout<<result<<endl; 
              } 
        catch(boost::bad_any_cast & ex) 
        { 
            cout<<"cast error:"<<ex.what()<<endl; 
        } 
    } 
} 

2.5執行緒庫

boost::thread類代表一個執行執行緒(a thread of execution),就像std::fstream類代表一個檔案一樣。預設建構函式建立一個代表當前執行執行緒的一個例項。過載建構函式則有一個函式物件作為引數,該函式物件沒有實參(argument),也無返回值。過載的建構函式建立一個新的執行緒,然後呼叫函式物件。
由於Boost.Threads採用了函式物件,而不是函式指標,因此函式物件攜帶執行緒要用到的資料是完全可以的。這種方法更加靈活,而且型別安全。如果再和相關的函式庫結合起來,比如Boost.Bind,這種方式可以讓你輕鬆地將任意多的資料傳遞給新建立的執行緒。

#include <boost/thread/thread.hpp>
#include <iostream>
void hello()
{
	std::cout << "Hello world, I'm a thread!" << std::endl;
}
int main(int argc, char* argv[])
{
	boost::thread thrd(&hello);		// 譯註:hello前面的&符號,可要可不要
	thrd.join();
 
	return 0;
}

不能讓多個執行緒同時訪問共享的資源是至關重要的。mutex在同一時間只能允許一個執行緒訪問共享資源。當一個執行緒需要訪問共享資源時,它必須先“鎖住”mutex,如果任何其他執行緒已經鎖住了mutex,那麼本操作將會一直被阻塞,直到鎖住了mutex的執行緒解鎖,這就保證了共享資源,在同一時間,只有一個執行緒可以訪問。
Boost.Threads支援兩大型別的mutex:簡單mutex和遞迴mutex。
一個執行緒有3種可能方法來鎖定mutex:
1. 等待並試圖對mutex加鎖,直到沒有其他執行緒鎖定mutex;
2. 試圖對mutex加鎖,並立即返回,如果其他執行緒鎖定了mutex;
3. 等待並試圖對mutex加鎖,直到沒有其他執行緒鎖定mutex或者直到規定的時間已過。
Boost.Threads允許你挑選最有效率的mutex。為此,Boost.Threads提供了6中型別的mutex,效率由高到低排列:boost::mutex,boost::try_mutex,boost::timed_mutex,boost::recursive_mutex,boost::recursive_try_mutex和boost::recursive_timed_mutex。

Boost.Threads提供Scoped Lock模式,防止死鎖。要構建一個這種型別的鎖,需要傳遞一個mutex引用,建構函式將鎖定mutex,解構函式將解鎖mutex

boost::mutex io_mutex;
struct count
{
	count(int id) : id(id) { } 
	void operator()()
	{
		for (int i = 0; i < 10; ++i)
		{
			boost::mutex::scoped_lock lock(io_mutex);
			std::cout << id << ": "	<< i << std::endl;
		}
	}
 	int id;
};
 
int main(int argc, char* argv[])
{
	boost::thread thrd1(count(1));
	boost::thread thrd2(count(2));
	thrd1.join();
	thrd2.join();
	
	return 0;
}

下面展示了Boost.Bind庫如何不寫函式物件

boost::mutex io_mutex;
void count(int id)
{
	for (int i = 0; i < 10; ++i)
	{
		boost::mutex::scoped_lock lock(io_mutex);
		std::cout << id << ": " << i << std::endl;
	}
}
 
int main(int argc, char* argv[])
{
	boost::thread thrd1(boost::bind(&count, 1));	// 有無&符號均可
	boost::thread thrd2(boost::bind(&count, 2));	// 有無&符號均可
	thrd1.join();
	thrd2.join();
 
	return 0;
}

 

相關文章