shared_ptr 的使用及注意事項

1. 聲明
#include <boost/shared_ptr.hpp>c++

class UsersBitmap {安全

...多線程

}函數

typedef boost::shared_ptr<UsersBitmap> UsersBitmapPtr;this

2. 使用線程

UsersBitmapPtr login_users_;
UsersBitmapPtr temp_login_users(new UsersBitmap());    //指向對象指針

login_users_.reset(new UsersBitmap());     //指針指向新的地方對象

login_users_.reset();  //指針置空內存

 

///////////////////////////////////////////////////////////////////////////get

////////////////////////////////////

雖然boost.shared_ptr是個很是好的東西,使用它可使得c++程序不須要考慮內存釋放的問題,可是仍是有不少必須注意的地方。下面羅列了一些本人在實際工做中常常碰到的使用shared_ptr出問題的幾種狀況。 1. shared_ptr屢次引用同一數據,以下:{int* pInt = new int[100];boost::shared_ptr<int> sp1(pInt);// 一些其它代碼以後…boost::shared_ptr<int> sp2(pInt);}這種狀況在實際中是很容易發生的,結果也是很是致命的,它會致使兩次釋放同一塊內存,而破壞堆。 2.使用shared_ptr包裝this指針帶來的問題,以下:class tester {public:  tester()  ~tester()  {    std::cout << "析構函數被調用!\n";   }public:  boost::shared_ptr<tester> sget()  {    return boost::shared_ptr<tester>(this);  }};int main(){  tester t;  boost::shared_ptr<tester> sp =  t.sget(); // …  return 0;}也將致使兩次釋放t對象破壞堆棧,一次是出棧時析構,一次就是shared_ptr析構。如有這種須要,可使用下面代碼。class tester : public boost::enable_shared_from_this<tester>{public:  tester()  ~tester()  {  std::cout << "析構函數被調用!\n";   }public:  boost::shared_ptr<tester> sget()  {  return shared_from_this();  }};int main(){  boost::shared_ptr<tester> sp(new tester);  // 正確使用sp 指針。  sp->sget();  return 0;}3. shared_ptr循環引用致使內存泄露,代碼以下:class parent;class child; typedef boost::shared_ptr<parent> parent_ptr;typedef boost::shared_ptr<child> child_ptr; class parent{public:       ~parent() {               std::cout <<"父類析構函數被調用.\n";        }public:       child_ptr children;};class child{public:       ~child() {               std::cout <<"子類析構函數被調用.\n";        }public:       parent_ptr parent;};int main(){  parent_ptr father(new parent());  child_ptr son(new child);  // 父子互相引用。  father->children = son;  son->parent = father;  return 0;}如上代碼,將在程序退出前,father的引用計數爲2,son的計數也爲2,退出時,shared_ptr所做操做就是簡單的將計數減1,若是爲0則釋放,顯然,這個狀況下,引用計數不爲0,因而形成father和son所指向的內存得不到釋放,致使內存泄露。 4. 在多線程程序中使用shared_ptr應注意的問題。代碼以下:class tester {public:  tester() {}  ~tester() {}  // 更多的函數定義…};void fun(boost::shared_ptr<tester> sp){  // !!!在這大量使用sp指針.  boost::shared_ptr<tester> tmp = sp;}int main(){  boost::shared_ptr<tester> sp1(new tester);  // 開啓兩個線程,並將智能指針傳入使用。  boost::thread t1(boost::bind(&fun, sp1));  boost::thread t2(boost::bind(&fun, sp1));  t1.join();  t2.join();  return 0;}這個代碼帶來的問題很顯然,因爲多線程同是訪問智能指針,並將其賦值到其它同類智能指針時,極可能發生兩個線程同時在操做引用計數(但並不必定絕對發生),而致使計數失敗或無效等狀況,從而致使程序崩潰,如若不知根源,就沒法查找這個bug,那就只能向上帝祈禱程序能正常運行。可能通常狀況下並不會寫出上面這樣的代碼,可是下面這種代碼與上面的代碼一樣,以下:class tester {public:  tester() {}  ~tester() {}public:  boost::shared_ptr<int> m_spData; // 可能其它類型。};tester gObject;void fun(void){  // !!!在這大量使用sp指針.  boost::shared_ptr<int> tmp = gObject.m_spData;}int main(){  // 多線程。  boost::thread t1(&fun);  boost::thread t2(&fun);  t1.join();  t2.join();  return 0;}狀況是同樣的。要解決這類問題的辦法也很簡單,使用boost.weak_ptr就能夠很方便解決這個問題。第一種狀況修改代碼以下:class tester {public:  tester() {}  ~tester() {}  // 更多的函數定義…};void fun(boost::weak_ptr<tester> wp){  boost::shared_ptr<tester> sp = wp.lock;  if (sp)  {    // 在這裏能夠安全的使用sp指針.  }  else  {    std::cout << 「指針已被釋放!」 << std::endl;  }} int main(){  boost::shared_ptr<tester> sp1(new tester);  boost.weak_ptr<tester> wp(sp1);  // 開啓兩個線程,並將智能指針傳入使用。  boost::thread t1(boost::bind(&fun, wp));  boost::thread t2(boost::bind(&fun, wp));  t1.join();  t2.join();  return 0;}boost.weak_ptr指針功能一點都不weak,weak_ptr是一種可構造、可賦值以不增長引用計數來管理shared_ptr的指針,它能夠方便的轉回到shared_ptr指針,使用weak_ptr.lock函數就能夠獲得一個shared_ptr的指針,若是該指針已經被其它地方釋放,它則返回一個空的shared_ptr,也可使用weak_ptr.expired()來判斷一個指針是否被釋放。boost.weak_ptr不只能夠解決多線程訪問帶來的安全問題,並且還能夠解決上面第三個問題循環引用。Children類代碼修改以下,便可打破循環引用:class child{public:  ~child() {    std::cout <<"子類析構函數被調用.\n";   }public:  boost::weak_ptr<parent> parent;};由於boost::weak_ptr不增長引用計數,因此能夠在退出函數域時,正確的析構。

相關文章
相關標籤/搜索