幾種智慧指標的比較(std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::weak_ptr)
一、std::auto_ptr
auto_ptr的建構函式接受原始指標作為引數,雖然它是一個物件,但是過載了operator*和operator->,可以把它用在大多數普通指標可用的地方。當退出作用域時,auto_ptr物件的解構函式會釋放原始指標。
例:
int main
{
auto_ptr<ClassA> p(new ClassA);
}
二、boost::scoped_ptr
scoped_ptr類摘要
scoped_ptr的建構函式接受一個型別為T*的指標p,建立一個scoped_ptr物件,並在內部儲存指標引數p。當scoped_ptr物件的生命期結束時,解構函式會自動銷燬儲存的指標物件。
boost::scoped_ptr和std::auto_ptr類似,但有不同。兩者都不能作為容器的元素。auto_ptr對指標的所有權是獨佔性的,在auto_ptr的複製建構函式內部,最後會將被拷貝物件內部的指標釋放掉。scoped_ptr不支援拷貝和賦值,拒絕了指標所有權的轉讓。
三、boost::shared_ptr
shared_ptr類摘要
shared_ptr與scoped_ptr一樣包裝了new操作符在堆上分配的動態物件,但它實現的是引用計數型的智慧指標,可以被自由地拷貝和賦值,當引用計數為0時,它才刪除被包裝的動態分配的物件。shared_ptr可以安全地放到標準容器中使用。
shared_ptr使用中應該注意:
(1)不要將物件的記憶體交給兩個shared_ptr管理。
(2)避免對shared_ptr所管理的物件的直接記憶體管理操作,以免造成該物件的重釋放。
(3)不要構造一個臨時的shared_ptr作為函式的引數。
(4)shared_ptr作為函式引數傳遞的時候可以採用引用,節省開銷。
(5)不能將T*直接賦值給一個智慧指標。
(6)不能寫ptr = NULL,應該使用ptr.reset()。
四、boost::weak_ptr
weak_ptr被設計為與shared_ptr共同工作,可以從一個shared_ptr或者另一個weak_ptr物件構造,獲得資源的觀測權。但weak_ptr沒有共享資源,它的構造不會引起指標引用計數的增加,析構時也不會導致引用計數的減少。它可以使用lock()函式從被觀測的shared_ptr獲得一個可用的shared_ptr物件,從而操作資源。但當expired()==true的時候,lock()將返回一個儲存空指標的shared_ptr。
weak_ptr一般用來打破迴圈引用所帶來的記憶體洩漏,例如下例:
class Teacher
{
public:
shared_ptr<Student> m_pStudent;
};
class Student
{
public:
shared_ptr<Teacher> m_pTeacher;
};
int main()
{
shared_ptr<Teacher> pTeacher(new Teacher);
shared_ptr<Student> pStudent(new Student);
pTeacher->m_pStudent = pStudent;
pStudent->m_pTeacher = pTeacher;
}
由於Teacher和Student的迴圈引用,在退出main函式後,pTeacher和pStudent的引用計數都不為0,造成記憶體洩漏。可以使用weak_ptr來解決這個問題。
class Student
{
public:
weak_ptr<Teacher> m_pTeacher;
}
最後值得一提的是,雖然通過弱引用指標可以有效的解除迴圈引用,但這種方式必須在程式設計師能預見會出現迴圈引用的情況下才能使用,也可以是說這個僅僅是一種編譯期的解決方案,如果程式在執行過程中出現了迴圈引用,還是會造成記憶體洩漏的。因此,不要認為只要使用了智慧指標便能杜絕記憶體洩漏。畢竟,對於C++來說,由於沒有垃圾回收機制,記憶體洩漏對每一個程式設計師來說都是一個非常頭痛的問題。