C++四種智能指針

為什么要使用智能指針:

智能指針的作用是管理一個指針,因為存在以下這種情況:申請的空間在函數(shù)結(jié)束時忘記釋放,造成內(nèi)存泄漏。使用智能指針可以很大程度上的避免這個問題,因為智能指針就是一個類,當(dāng)超出了類的作用域是,類會自動調(diào)用析構(gòu)函數(shù),析構(gòu)函數(shù)會自動釋放資源。所以智能指針的作用原理就是在函數(shù)結(jié)束時自動釋放內(nèi)存空間,不需要手動釋放內(nèi)存空間。

1. auto_ptr(c++98的方案,cpp11已經(jīng)拋棄)

采用所有權(quán)模式。

auto_ptr< string> p1 (new string ("I reigned lonely as a cloud.”));
auto_ptr<string> p2;
p2 = p1; //auto_ptr不會報錯.

此時不會報錯,p2剝奪了p1的所有權(quán),但是當(dāng)程序運行時訪問p1將會報錯。所以auto_ptr的缺點是:存在潛在的內(nèi)存崩潰問題!

2. unique_ptr(替換auto_ptr)

unique_ptr實現(xiàn)獨占式擁有或嚴格擁有概念,保證同一時間內(nèi)只有一個智能指針可以指向該對象。它對于避免資源泄露(例如“以new創(chuàng)建對象后因為發(fā)生異常而忘記調(diào)用delete”)特別有用。

unique_ptr<string> p3 (new string ("auto"));   //#4
unique_ptr<string> p4;                       //#5
p4 = p3;//此時會報錯??!

當(dāng)程序試圖將一個 unique_ptr 賦值給另一個時,如果源 unique_ptr 是個臨時右值,編譯器允許這么做;如果源 unique_ptr 將存在一段時間,編譯器將禁止這么做,比如:

unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1;                                      // #1 not allowed
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You"));   // #2 allowed

其中#1留下懸掛的unique_ptr(pu1),這可能導(dǎo)致危害。而#2不會留下懸掛的unique_ptr,因為它調(diào)用 unique_ptr 的構(gòu)造函數(shù),該構(gòu)造函數(shù)創(chuàng)建的臨時對象在其所有權(quán)讓給 pu3 后就會被銷毀。這種隨情況而已的行為表明,unique_ptr 優(yōu)于允許兩種賦值的auto_ptr 。

如果確實想執(zhí)行類似與#1的操作,要安全的重用這種指針,可給它賦新值。C++有一個標(biāo)準(zhǔn)庫函數(shù)std::move(),讓你能夠?qū)⒁粋€unique_ptr賦給另一個。例如:

unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;
3. shared_ptr

shared_ptr實現(xiàn)共享式擁有概念。多個智能指針可以指向相同對象,該對象和其相關(guān)資源會在“最后一個引用被銷毀”時候釋放。除了可以通過new來構(gòu)造,還可以通過傳入auto_ptr, unique_ptr,weak_ptr來構(gòu)造。當(dāng)我們調(diào)用release()時,當(dāng)前指針會釋放資源所有權(quán),計數(shù)減一。當(dāng)計數(shù)等于0時,資源會被釋放。

成員函數(shù):

  • use_count 返回引用計數(shù)的個數(shù)
  • unique 返回是否是獨占所有權(quán)( use_count 為 1)
  • swap 交換兩個 shared_ptr 對象(即交換所擁有的對象)
  • reset 放棄內(nèi)部對象的所有權(quán)或擁有對象的變更, 會引起原有對象的引用計數(shù)的減少
  • get 返回內(nèi)部對象(指針), 由于已經(jīng)重載了()方法, 因此和直接使用對象是一樣的.如 shared_ptr<int> sp(new int(1)); sp 與 sp.get()是等價的
4. weak_ptr

weak_ptr 是一種不控制對象生命周期的智能指針, 它指向一個 shared_ptr 管理的對象. 進行該對象的內(nèi)存管理的是那個強引用的 shared_ptr. weak_ptr只是提供了對管理對象的一個訪問手段。weak_ptr 設(shè)計的目的是為配合 shared_ptr 而引入的一種智能指針來協(xié)助 shared_ptr 工作, 它只可以從一個 shared_ptr 或另一個 weak_ptr 對象構(gòu)造, 它的構(gòu)造和析構(gòu)不會引起引用記數(shù)的增加或減少。weak_ptr是用來解決shared_ptr相互引用時的死鎖問題,如果說兩個shared_ptr相互引用,那么這兩個指針的引用計數(shù)永遠不可能下降為0,資源永遠不會釋放。它是對對象的一種弱引用,不會增加對象的引用計數(shù),和shared_ptr之間可以相互轉(zhuǎn)化,shared_ptr可以直接賦值給它,它可以通過調(diào)用lock函數(shù)來獲得shared_ptr。

class B;
class A
{
public:
  shared_ptr<B> pb_;
  ~A()
  {
    cout<<"A delete\n";
  }
};

class B
{
public:
  shared_ptr<A> pa_;
  ~B()
  {
    cout<<"B delete\n";
  }
};

void fun()
{
  shared_ptr<B> pb(new B());
  shared_ptr<A> pa(new A());
  pb->pa_ = pa;
  pa->pb_ = pb;
  cout<<pb.use_count()<<endl;
  cout<<pa.use_count()<<endl;
}

int main()
{
  fun();
return 0;
}

把其中一個改為weak_ptr就可以了。

注意的是我們不能通過weak_ptr直接訪問對象的方法,比如B對象中有一個方法print(),我們不能這樣訪問,pa->pb_->print(); 英文pb_是一個weak_ptr,應(yīng)該先把它轉(zhuǎn)化為shared_ptr,如:shared_ptr p = pa->pb_.lock(); p->print();

野指針

野指針就是指向一個已刪除的對象或者未申請訪問受限內(nèi)存區(qū)域的指針。

智能指針有沒有內(nèi)存泄露的情況

有, 當(dāng)兩個對象相互使用一個shared_ptr成員變量指向?qū)Ψ?,會造成循環(huán)引用,使引用計數(shù)失效,從而導(dǎo)致內(nèi)存泄漏。
解決方式:weak_ptr弱指針。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 導(dǎo)語: C++指針的內(nèi)存管理相信是大部分C++入門程序員的夢魘,受到Boost的啟發(fā),C++11標(biāo)準(zhǔn)推出了智能指針...
    7ee72f98ad17閱讀 1,037評論 0 1
  • 參考資料:《C++ Primer中文版 第五版》我們知道除了靜態(tài)內(nèi)存和棧內(nèi)存外,每個程序還有一個內(nèi)存池,這部分內(nèi)存...
    陳星空閱讀 1,123評論 0 0
  • 原作者:Babu_Abdulsalam 本文翻譯自CodeProject,轉(zhuǎn)載請注明出處。 引入### Ooops...
    卡巴拉的樹閱讀 30,364評論 13 74
  • C++裸指針的內(nèi)存問題有:1、空懸指針/野指針2、重復(fù)釋放3、內(nèi)存泄漏4、不配對的申請與釋放 使用智能指針可以有效...
    WalkeR_ZG閱讀 3,288評論 0 5
  • 拍照時間:2019年7月8日 拍攝地點:城市花園婚紗影城 化妝師:杜鵑 攝影師:胡彥許 //A.林間夢境// //...
    大果粒zigzag閱讀 66評論 0 0

友情鏈接更多精彩內(nèi)容