【C++】智能指標__C++

來源:互聯網
上載者:User
1.智能指標的作用

       C++程式設計中使用堆記憶體是非常頻繁的操作,堆記憶體的申請和釋放都由程式員自己管理。程式員自己管理堆記憶體可以提高了程式的效率,但是整體來說堆記憶體的管理是麻煩的,C++11中引入了智能指標的概念,方便管理堆記憶體。使用普通指標,容易造成堆記憶體泄露(忘記釋放),二次釋放,程式發生異常時記憶體泄露等問題等,使用智能指標能更好的管理堆記憶體。

理解智能指標需要從下面三個層次: 從較淺的層面看,智能指標是利用了一種叫做RAII(資源擷取即初始化)的技術對普通的指標進行封裝,這使得智能指標實質是一個對象,行為表現的卻像一個指標。 智能指標的作用是防止忘記調用delete釋放記憶體和程式異常的進入catch塊忘記釋放記憶體。另外指標的釋放時機也是非常有考究的,多次釋放同一個指標會造成程式崩潰,這些都可以通過智能指標來解決。 智能指標還有一個作用是把值語義轉換成引用語義。 2.智能指標的使用

智能指標在C++11版本之後提供,包含在標頭檔<memory>中,aauto_ptr,shared_ptr、unique_ptr、weak_ptr 2.1、auto_ptr 的使用 auto_ptr 有很多問題。不支援複製(拷貝建構函式)和複製(operator = ),但複製或賦值的時候不會提示出錯。因為不能被複製,所以不能被放入容器中。
2.2、 shared_ptr 的使用

shared_ptr多個指標指向相同的對象。shared_ptr使用引用計數,每一個shared_ptr的拷貝都指向相同的記憶體。每使用他一次,內部的引用計數加1,每析構一次,內部的引用計數減1,減為0時,自動刪除所指向的堆記憶體。shared_ptr內部的引用計數是安全執行緒的,但是對象的讀取需要加鎖。 初始化。智能指標是個模板類,可以指定類型,傳入指標通過建構函式初始化。也可以使用make_shared函數初始化。不能將指標直接賦值給一個智能指標,一個是類,一個是指標。例如std::shared_ptr<int> p4 = new int(1);的寫法是錯誤的 拷貝和賦值。拷貝使得對象的引用計數增加1,賦值使得原對象引用計數減1,當計數為0時,自動釋放記憶體。後來指向的對象引用計數加1,指向後來的對象。 get函數擷取原始指標 注意不要用一個原始指標初始化多個shared_ptr,否則會造成二次釋放同一記憶體 注意避免循環參考,shared_ptr的一個最大的陷阱是循環參考,迴圈,循環參考會導致堆記憶體無法正確釋放,導致記憶體流失。循環參考在weak_ptr中介紹。

#include<iostream>#include<memory>using namespace std;// share_ptrint main(void){{int a = 10;shared_ptr<int> ptra = make_shared<int>(a);shared_ptr<int> ptra2(ptra);cout << ptra.use_count() << endl;int b = 20;int *pb = &a;shared_ptr<int> ptrb = make_shared<int>(b);ptra2 = ptrb;pb = ptrb.get();cout << ptra.use_count() << endl;cout << ptrb.use_count() << endl;}return 0;}

2.2 unique_ptr的使用

  unique_ptr“唯一”擁有其所指對象,同一時刻只能有一個unique_ptr指向給定對象(通過禁止拷貝語義、只有移動語意來實現)。相比與原始指標unique_ptr用於其RAII的特性,使得在出現異常的情況下,動態資源能得到釋放。unique_ptr指標本身的生命週期:從unique_ptr指標建立時開始,直到離開範圍。離開範圍時,若其指向對象,則將其所指對象銷毀(預設使用delete操作符,使用者可指定其他動作)。unique_ptr指標與其所指對象的關係:在智能指標生命週期內,可以改變智能指標所指對象,如建立智能指標時通過建構函式指定、通過reset方法重新指定、通過release方法釋放所有權、通過移動語意轉移所有權。

// unique_ptrint main(void){{// 綁定動態對象unique_ptr<int> uptr(new int(10));// unique_ptr<int> uptr2 = uptr;不能賦值// unique_ptr<int> uptr3(uptr);          不能拷貝unique_ptr<int> uptr4 = move(uptr);   // 轉換所有權uptr4.release();// 釋放所有權}// 超過 uptr 的範圍,記憶體釋放return 0;}


2.3 weak_ptr的使用

  weak_ptr是為了配合shared_ptr而引入的一種智能指標,因為它不具有普通指標的行為,沒有重載operator*和->,它的最大作用在於協助shared_ptr工作,像旁觀者那樣觀測資源的使用方式。weak_ptr可以從一個shared_ptr或者另一個weak_ptr物件建構,獲得資源的觀測權。但weak_ptr沒有共用資源,它的構造不會引起指標引用計數的增加。使用weak_ptr的成員函數use_count()可以觀測資源的引用計數,另一個成員函數expired()的功能等價於use_count()==0,但更快,表示被觀測的資源(也就是shared_ptr的管理的資源)已經不複存在。weak_ptr可以使用一個非常重要的成員函數lock()從被觀測的shared_ptr獲得一個可用的shared_ptr對象, 從而操作資源。但當expired()==true的時候,lock()函數將返回一個儲存null 指標的shared_ptr。

// weak_ptrint main(){{shared_ptr<int> sh_ptr = make_shared<int>(10);cout << sh_ptr.use_count() << endl;weak_ptr<int> wp(sh_ptr);cout << wp.use_count() << endl;if (!wp.expired()){shared_ptr<int> sh_ptr2 = wp.lock();*sh_ptr = 100;cout << wp.use_count() << endl;}}return 0;}

3.智能指標的設計和實現

  下面是一個簡單智能指標的demo。智能指標類將一個計數器與類指向的對象相關聯,引用計數跟蹤該類有多少個對象共用同一指標。每次建立類的新對象時,初始化指標並將引用計數置為1;當對象作為另一對象的副本而建立時,拷貝建構函式拷貝指標並增加與之相應的引用計數;對一個對象進行賦值時,賦值操作符減少左運算元所指對象的引用計數(如果引用計數為減至0,則刪除對象),並增加右運算元所指對象的引用計數;調用解構函式時,建構函式減少引用計數(如果引用計數減至0,則刪除基礎對象)。智能指標就是類比指標動作的類。所有的智能指標都會重載 -> 和 * 操作符。智能指標還有許多其他功能,比較有用的是自動銷毀。這主要是利用棧對象的有限範圍以及臨時對象(有限範圍實現)解構函式釋放記憶體。

// 類比實現智能指標#include<iostream>#include<assert.h>using namespace std;template<typename T>class SmartPointer{private:T *_ptr;size_t *_count;public:SmartPointer(T *ptr = NULL):_ptr(ptr){if (_ptr)_count = new size_t(1);else_count = new size_t(0);}SmartPointer(const SmartPointer &ptr){if (this != &ptr){this->_ptr = ptr._ptr;this->_count = ptr._count;(*this->_count)++;}}SmartPointer &operator=(SmartPointer &ptr){if (this->_ptr == ptr._ptr)return*this;if (this->_ptr){(*this->_count)--;if (this->_count == 0){delete this->_ptr;delete this->_count;}}this->_ptr = ptr._ptr;this->_count = ptr._count;(*this->_count)++;return *this;}T & operator*(){assert(this->_ptr == NULL);return this->_ptr;}~SmartPointer(){(*this->_count)--;if (*this->_count == 0){delete this->_ptr;delete this->_count;}}size_t use_count(){return *this->_count;}};int main(void){SmartPointer<int> sp(new int(10));SmartPointer<int> sp2(sp);SmartPointer<int> sp3(new int(20));sp2 = sp3;cout << sp.use_count() << endl;cout << sp2.use_count() << endl;cout << sp3.use_count() << endl;return 0;}

4、常見 C++ 智能指標面試

 4.1,你知道智能指標嗎。智能指標的原理。

  答案:智能指標是一個類,這個類的建構函式中傳入一個普通指標,解構函式中釋放傳入的指標。智能指標的類都是棧上的對象,所以當函數(或程式)結束時會自動被釋放,

4.2,常用的智能指標。    

              1)std::auto_ptr,有很多問題。 不支援複製(拷貝建構函式)和賦值(operator =),但複製或賦值的時候不會提示出錯。因為不能被複製,所以不能被放入容器中。

              2) C++11引入的unique_ptr, 也不支援複製和賦值,但比auto_ptr好,直接賦值會編譯出錯。實在想賦值的話,需要使用:std::move。

               例如:

                    std::unique_ptr<int> p1(new int(5));
                    std::unique_ptr<int> p2 = p1; // 編譯會出錯
                    std::unique_ptr<int> p3 = std::move(p1); // 轉移所有權, 現在那塊記憶體歸p3所有, p1成為無效的指標.

              3) C++11或boost的shared_ptr,基於引用計數的智能指標。可隨意賦值,直到記憶體的引用計數為0的時候這個記憶體會被釋放。

              4)C++11或boost的weak_ptr,弱引用。 引用計數有一個問題就是互相引用形成環,這樣兩個指標指向的記憶體都無法釋放。需要手動打破迴圈

引用或使用weak_ptr。顧名思義,weak_ptr是一個弱引用,只引用,不計數。如果一塊記憶體被shared_ptr和weak_ptr同時引用,當所有shared_ptr

析構了之後,不管還有沒有weak_ptr引用該記憶體,記憶體也會被釋放。所以weak_ptr不保證它指向的記憶體一定是有效,在使用之前需要檢查weak_ptr是

否為空白指標。  4.3,智能指標的實現。
參考文章: https://www.cnblogs.com/wxquare/p/4759020.html https://blog.csdn.net/bian_qing_quan11/article/details/73333214

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.