Boost筆記


如下是閱讀“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:

· 從字符串類型到數值類型的轉換

· 從數值類型到字符串類型的轉換

· 你的自定義類型所支持的所有字面轉換


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM