為管理記憶體等資源,c++採取raii機制(資源獲取即初始化,resource acquisition is initialization),在使用資源的類的建構函式中申請資源並使用,最終在析構函式中釋放資源。使用new在堆上建立物件時,其析構函式不會自動呼叫,需要使用delete才能釋放資源,若因為異常導致程式未能執行delete,則存在記憶體洩露的問題。c++98標準中的「自動指標std::auto_ptr(c++11中廢棄,改用unique_ptr)部分解決了獲取資源自動釋放的問題。
boost.smart_ptr庫提供六種智慧型指標,包括socped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr和intrusive_ptr。他們都是輕量級的物件,速度與原始指標相差無幾,都是異常安全的,而且對於所指向的型別t也僅有乙個很小且合理的要求:型別t的析構函式不能丟擲異常。
標頭檔案:#include
scoped_ptr
保證智慧型指標只能在本作用域中使用,擁有物件的唯一所有權,不可以複製。如果乙個類中有scoped_ptr成員變數,則該類也不可拷貝或賦值。
scoped_array
類似scoped_ptr,只不過包裝的是new[ ]操作符,不推薦使用
shared_ptr
實現了引用計數,可以拷貝或賦值,當引用計數為0時自動刪除動態分配的物件
shared_array
類似shared_ptr,但包裝的是new[ ]分配的動態陣列
weak_ptr
配合shared_ptr而引入,不具備普通指標的行為,作為shared_ptr擁有物件的非擁有觀察者
intrusive_ptr
引用計數型智慧型指標,可以包裝已有物件得到與shar_ptr類似的智慧型指標
scoped_ptr包裝了new操作符在堆上分配的動態物件,能夠保證動態建立的物件在任何時候都可以被正確地刪除,scoped_ptr獲取物件管理權後就不能再轉讓。
scoped_ptr的建構函式接受乙個型別為t*的指標p,建立出乙個scoped_ptr物件,並在內部儲存指標引數p。p必須是new表示式動態分配的結果,或者是乙個空指標(nullptr)。當scoped_ptr物件的生命期結束時,析構函式~scoped_ptr()會使用delete操作符自動銷毀所儲存的指標物件來正確**資源。拷貝建構函式和賦值操作符被宣告為私有的,禁止對智慧型指標的拷貝操作,保證了被它管理的指標不能被轉讓所有權。
scoped_ptr提供在bool語境(如if的條件表示式)中自動轉換成bool值的功能,用來測試scoped_ptr是否持有乙個有效的指標(非空),可以替代與空指標的比較操作(有限比較,僅能與空指標進行比較操作)。
#includeusing namespace boost;
struct posix_file
~posix_file()
}int main() //這裡scoped_array被自動析構,釋放動態陣列資源
shared_ptr是最像指標的」智慧型指標「,是boost.smart_ptr庫中最有價值、最重要、最有用的組成部分。他包裝了new操作符在堆上分配的動態物件,實現了引用計數,可以自由地拷貝和賦值,在任意地方進行共享。也可以安全地放到標準容器中,是在stl容器中儲存指標的最標準解法。
shared_ptr有多種形式的建構函式,應用於可能的情形:
reset()函式將shared_ptr的引用計數減1,停止對指標的共享,除非引用計數為0,否則不會發生刪除操作;帶引數的reset()類似相同形式的建構函式,原引用計數減1的同時改為管理另乙個指標。
unique()和use_count()專門用來檢查引用計數,unique()在指標是唯一所有者時返回true,是可靠的,任何時候都可用;use_count()返回當前指標的引用計數,不提供高效率的操作。
shared_ptr支援比較運算,可以測試兩個shared_ptr的相等或不相等,比較基於內部儲存的指標,相當於a.get() == b.get();還可以使用operator《比較大小,但不提供除此外的比較操作符。
此外shared_ptr還支援流輸出操作符operator<< ,輸出內部的指標值,方便除錯。
class shared
void print()
工廠函式make_shared()可以接受若干引數,然後把它們傳遞給型別t的建構函式,建立乙個shared_ptr物件並返回。這要比直接建立shared_ptr物件的方式快且高效,因為內部僅分配了一次記憶體,消除了shared_ptr構造時的開銷。allocate_shared()與make_shared()相同,但多乙個定製的記憶體分配器型別引數。
auto sp = make_shared("make_shared"); //建立string的共享指標
auto spv = make_shared>(10,2); //建立vector的共享指標
shared_ptr應用於標準容器、應用於橋接模式、應用於工廠函式、定製刪除器.......
shared_array與shared_ptr基本相同,具有shared_ptr的優點和scoped_array的缺點,主要區別:
#includeusing namespace boost;
int main //離開作用域,自動刪除動態陣列
shared_array不提供陣列索引的範圍檢查,如果使用超過動態陣列大小的索引或負索引將引發未定義行為。
weak_ptr被設計與shared_ptr協同工作,可以從乙個shared_ptr或另乙個weak_ptr物件構造,獲得資源的觀察權,構造和析構不會引起指標引用計數的增加或減少。
use_count()可以觀測資源的引用計數,expired()的功能等價於use_count()==0,但更快,表示被觀測的資源不復存在。lock()從被觀測的shared_ptr獲得乙個可用的shared_ptr物件,把弱關係轉換為強關係,從而操作資源,當expired()==true時,lock()返回空指標的shared_ptr。
weak_ptr乙個重要用途是獲取this指標的shared_ptr,使物件能夠自己生產shared_ptr管理自己:物件使用weak_ptr觀測this指標,這並不影響引用計數,需要時呼叫lock()函式,返回乙個符合要求的shared_ptr供外界使用。成員函式shared_from_this()會返回this的shared_ptr。使用方法:
class self_shared :
public enable_shared_from_this
int x;
void print()
};int main()
與enable_shared_from_this類似,但不要求物件必須被乙個shared_ptr管理,可以直接從乙個原始指標建立出shared_ptr。
#includeclass raw_shared : public boost::enable_shared_from_raw
~raw_shared()
};int main() //物件自動刪除
****現「迴圈引用」時,shared_ptr的引用機制會失效,導致不能正確析構釋放資源。使用weak_ptr在可能存在迴圈引用的地方打破迴圈,在需要shared_ptr的時候呼叫weak_ptr的lock()函式。
class node;
int main()
} //退出作用域,shared_ptr均正確析構
intrusive_ptr介面與shared_ptr很像,同樣支援比較和static_pointer_cast()、dynamic_pointer_cast()等轉型操作,但不直接管理引用計數,而是呼叫函式來間接管理:
void intrusive_ptr_add_ref(t *p); //增加引用計數
void intrusive_ptr_release(t *p); //減少引用計數
intrusive_ptr建構函式和reset()多出乙個bool add_ref引數,表示是否增加引用計數,如果add_ref == true,那麼它就相當於weak_ptr,只是簡單地觀察物件。
boost程式庫完全開發指南:深入c++「準」標準庫
如何理解智慧型指標? 知乎
c++智慧型指標簡單剖析 注:
assert是c/c++提供的準確性驗證、測試支援的巨集,詳見 boost程式庫完全開發指南第6章:正確性與測試
boost 智慧型指標
boost shared ptr 的記憶體管理機制 boost shared ptr 的管理機制其實並不複雜,就是對所管理的物件進行了引用計數,當新增乙個 boost shared ptr 對該物件進行管理時,就將該物件的引用計數加一 減少乙個 boost shared ptr 對該物件進行管理時,...
boost 智慧型指標
最近使用boost的智慧型指標,檢視了一些帖子。總結如下 智慧型指標分類 智慧型指標使用注意事項 多執行緒安全性分析 這個帖子的結論很好,1 shared ptr是乙個非常實用的智慧型指標。2 shared ptr的實現機制是在拷貝構造時使用同乙份引用計數。3 對同乙個shared ptr的寫操作不...
boost 智慧型指標
shared 指標類似於乙個帶計數器的指標,當指標計數次數為0時,它將自動析構物件。shared ptr指標可通過一次new出來,一直向下傳遞,直到每次析構shared ptr時將該指標引用量 1 注 每次進行不帶引用的傳遞時呼叫次數會加1,但析構時同時會 1,若用引用傳遞,每次呼叫值不增加,但同樣...