c++11之智能指針


  在c++98中,智能指針通過一個模板“auto_ptr”來實現,auto_ptr以對象的方式來管理堆分配的內存,在適當的時間(比如析構),釋放所獲得的內存。這種內存管理的方式只需要程序員將new操作返回的指針作為auto_ptr的初始值即可,程序員不能顯式的調用delete。如 auto_ptr(new int)。

  這在一定程度上避免了堆內存忘記釋放造成的問題。不過auto_ptr也有一些缺點(拷貝是返回一個左值,不能調用delete[]等),所以在c++11中被廢棄了。c++11標准照中改用unique_ptr,share_ptr,及weak_ptr等智能指針自動回收堆分配的對象。

  下面是一個用c++11中智能指針實現的一個例子:

#include <memory>
#include <iostream>

using namespace std;

int main()
{
    unique_ptr<int> up1(new int(11));  //無法復制的unique_ptr
    unique_ptr<int> up2 = up1;         //不能通過編譯
    
    cout << *up1 << endl;        //11
    
    unique_ptr up3 = move(up1);  //現在up3是數據唯一的unique_ptr只能指針
    
    cout << *up3 << endl;       //11
    cout << *up1 << endl;       //運行時錯誤
    up3.reset();                //顯示釋放內存
    up1.reset();                //不會導致運行時錯誤
    
    cout << *up3 << endl;       //運行時錯誤
    
    share_ptr<int> sp1(new int(22));
    share_ptr<int> sp2 = sp1;   //OK
    
    cout << *sp1 << endl;       //22
    cout << *sp2 << endl;       //22
    
    sp1.reset();
    cout << *sp2 << endl;       //22
}

  例子使用兩種不同的智能指針unique_ptr和share_ptr來自動釋放堆對象的內存。在析構或者調用reset都能釋放對象。

  unique_ptr與所指的對象內存綁定緊密,不能與其他的unique_ptr類型的指針共享所指對象的內存。每個unique_ptr都唯一的擁有所指對象的內存。但是這種所有權可以通過標准庫的move函數來轉移,如unique_ptr up3 = move(up1),一旦轉移成功,原先的 unique_ptr就失去了對象內存的所有權,再使用已經失去權力的unique_ptr就會出現運行錯誤。

  從實現上講,unique_ptr是刪除了拷貝構造函數,保留了移動構造函數的封裝類型,程序僅可以使用右值對unique_ptr進行構造,一旦構造成功,右值對象中的指針失效。

  share_ptr則不同,它允許多個該智能指針共享的永遠同一堆分配對象的內存。與unique_ptr不同的是在實現上采用了引用計數,所以,一旦某個share_ptr失去了所有權,其他指針並沒有影響,例子中sp1和sp2都共享指針,在sp1 reset之后只會使計數器降低,而不會導致內存的釋放,當sp2 reset之后,導致引用計數器為零,share_ptr才會真正釋放占有的內存空間。

  在c++11標准中,除了share_ptr和unique_ptr之外 ,還有weak_ptr。

  weak_ptr是一種不控制所指向對象生存期的智能指針,它指向一個shared_ptr管理的對象,卻並不擁有該對象。將一個weak_ptr綁定到shared_ptr不會改變shared_ptr的引用計數。一旦最后一個指向對象的shared_ptr被銷毀,對象就會被釋放,即使有weak_ptr指向對象,對象還是會被釋放。

  當我們創建一個weak_ptr時,要用一個shared_ptr來初始化它:

auto p=make_shared_ptr<int>(42);

weak_ptr<int> wp(p); //wp弱共享p,p的引用計數未改變

  由於對象可能不存在,我們不能使用weak_ptr直接訪問對象,而必須調用lock()。此函數檢查weak_ptr指向的對象是否存在。使用weak_ptr的成員lock,則可返回內存中的一個share_ptr對象,並在所指向的對象無效時候,返回空。

#include <memeroy>
#include <iostream>

using namespace std;

void Check(weal_ptr<int> & wp)
{
    share_ptr<int> sp = wp.lock();  //轉換為share_ptr<int>
    if(sp != nullptr)
    {
        cout << "still" << *sp << endl;
    }
    else
    {
        cout << "pointer is invalid." << endl;
    }
}

int main()
{
    share_ptr<int> sp1(new int(22));
    share_ptr<int> sp2 = sp1;
    weal_ptr<int> wp = sp1;//指向share_ptr<int> 所指對象
    
    cout << *sp1 << endl;  //22
    cout << *sp2 << endl;  //22
    Check(wp);             //still 22
    
    sp1.reset();
    cout << *sp2 << endl;  //22
    Check(wp);           //still 22
    
    sp2.reset();
    Check(wp);           //pointer is invalid.
    
    return 0;
}

  例子中,sp1和sp2為共享對象,而weak_ptr指針wp也指向該內存,在sp1和sp2都有效的時候,調用weak_ptr的lock函數返回一個可用的share_ptr使用;當sp1和sp2都調用reset之后,會使堆內存的引用計數器降低為0,而一旦計數器降低為0,share_ptr就會釋放內存,使之失效,此時調用weak_ptr的lock時,返回空指針nullptr。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM