這裏只是介紹智能用法和注意事項,簡單介紹其原理,如果想深入瞭解其實現的同學可以繞道。
- 爲什麼用智能指針:在編寫服務器代碼的時候,經常會出現new對象的情況,比如遊戲服務器中,一個新玩家上線了,需要new player,放到mapAllPlayer中,直到玩家下線才能刪除。但是在玩家下線時,可能調用了map.erese(),忘記delete指針,或者都忘記了,就會造成內存泄漏,也就是內存不斷瘋長,直到程序崩掉。
- 智能指針的分類:auto_ptr,unique_ptr,shared_ptr.三種,但是auto_ptr因其缺點,已經被棄用,最好不要使用他,後兩者是C++11爲我們提供的新型智能指針。
- 使用智能指針:
要想使用智能指針,首先先了解下智能指針模板的定義,實際上智能指針就是封裝好的三個類。template<class X> class auto_ptr { public: explicit auto_ptr(X* p = 0); ... }
//正常使用 class A; //已定義好的class A、 std::auto_ptr<A> ps(new A()); std::shared_ptr<A> ps(new A()); std::unique_ptr<A> ps(new A()); //錯誤使用: shared_ptr<double> pd; double* p_reg = new double; pd = p_reg; //這是不允許的,這種實際上是在調用pd的賦值運算符,不允許將非智能指針賦值給智能指針 shared_ptr<double> pshared = p_reg; //不允許,這是在隱式調用構造函數,explicit不允許隱身調用。 shared_ptr<double> pshared(p_reg); //允許的,正常調用構造函數 pd = shared_ptr<double>(p_reg); //這是允許的,實際上這是先創建一個智能指針的臨時變量, //然後調用賦值運算符,將智能指針賦值給智能指針。
但是一定要避免一種情況,使用臨時變量去構造智能指針,如
string str("hello,wordl");
shared_ptr<string> ptr(&str); 這是絕對拒絕的 - 關於幾種指針的區別,和注意事項:
這裏必須強調一句,智能指針也不是絕對智能的,必須合理使用。
說一種特殊情況:在調用複製構造函數時,常常遇到指針賦值,如下面代碼:A::A() { m_pstr = new string(); } A::A(const A& a) { m_pstr = a.m_pstr; }
a.建立所有權關係:對一個對象,只有一個智能指針能擁有他,當賦值操作時,轉讓所有權,舊的指針不在有意義。這是auto_ptr和unique_ptr的策略。
b.創建智能更高的指針,跟蹤引用該對象的智能指針數,稱爲引用計數,賦值時,引用數加一,指針過期時,引用次數減一,最後一個指針過期時,該對象被銷燬。
光說概念,可能不懂什麼是所有權,什麼是引用,下面寫一段簡單代碼,請看完,很有用:#include <iostream> #include <memory> #include <string> using namespace std; int main() { auto_ptr<double> pSrc(new double(2.0)); cout << *pSrc << endl; auto_ptr<double> pNex = pSrc; cout << *pNex << endl; cout << *pSrc << endl; return 1; }
unique<int> func() { unique<int> *p(new int); return p; } unique_ptr<int> ps = func() //是允許的,因爲其不會造成任何懸掛指針,返回的臨時指針及時被銷燬了 //使用std::move函數可以將所有權賦給新的一個,但是還是不安全的 unique_ptr<int> ps1; ps1 = std::move(ps); //此時ps變爲懸掛指針,必須賦新值纔可以使用
如果非要進行賦值操作。那麼怎麼辦,就要用到shared_ptr,他允許賦值,會增加一次引用,將上面代碼的auto改爲shared就可以解決崩潰問題。 - 如何選擇智能指針:
要根據需求,如果該指針引用的對象要參與賦值操作,需要使用shared_ptr,如果不參與賦值,則可以使用unique_ptr.最好不要使用auto_ptr指針。
還有一點需要注意:如果不是用new出來的指針,三個智能指針都是不能使用的,unique支持new[],其他兩個不支持。