日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++智能指针详解【C++智能指针】

發(fā)布時(shí)間:2025/3/20 c/c++ 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++智能指针详解【C++智能指针】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  • 自動(dòng)內(nèi)存管理
    • 智能指針
    • 什么是 RAII
    • 原理
    • 智能指針的模板(template)實(shí)現(xiàn)
  • auto_ptr
    • auto_ptr 使用
    • 重載函數(shù) operator-> / *語法格式
    • 自實(shí)現(xiàn) auto_ptr
    • auto_ptr被廢棄的原因
  • unique_ptr
    • unique_ptr使用
    • 常用接口
  • shared_ptr
    • 原理
    • 常用接口
    • 移動(dòng)和傳遞引用
  • 小結(jié)
    • unique_ptr可用于托管堆內(nèi)存數(shù)組。(官方僅支持unique_ptr)
    • shared_ptr不可用于托管堆內(nèi)存數(shù)組。(官方不支持)

自動(dòng)內(nèi)存管理

智能指針

一套成熟的類庫,通常都會(huì)引用內(nèi)存管理機(jī)制。
例如:Cocos,Qt等

C++在語言層面也提供了內(nèi)存管理機(jī)制,即智能指針 auto_ptr。
雖然 auto_ptr 己經(jīng) deserted 了(引自 Google C++ 編程規(guī)范),但是它的后繼者,諸如 share_ptr, weak_ptr 靈感均取自于auto_ptr。

什么是 RAII

RAII(Resource Acquisition Is Initialization),也稱為"資源獲取即初始化",是 C++語言的一種管理資源、避免泄漏的慣用法。

RAII是一種利用對象生命周期來控制程序資源的簡單技術(shù)。
程序資源包括:內(nèi)存、文件句柄、網(wǎng)絡(luò)連接、互斥量等等。

C++中的構(gòu)造器和析構(gòu)器就是根據(jù)RAII思想設(shè)計(jì)。

C++標(biāo)準(zhǔn)保證任何情況下,已構(gòu)造的對象最終會(huì)銷毀,即它的析構(gòu)函數(shù)最終會(huì)被調(diào)用。

有構(gòu)造就一定有析構(gòu)。

RAII一般做法:
簡單的說,RAII 的做法是使一個(gè)對象,在其構(gòu)造時(shí)獲取資源,在對象生命期控制對資源的訪問使之始終保持有效,最后在對象生命期結(jié)束時(shí)析構(gòu)進(jìn)行資源釋放。

注意理解:在類對象包裝其他對象資源時(shí),通過NEW獲取其他對象資源,通過構(gòu)造進(jìn)行其他對象資源初始化,通過析構(gòu)在其他對象消失時(shí)進(jìn)行資源釋放。

其實(shí)也就是把管理一份資源的責(zé)任托管給了一個(gè)對象。

好處:
①:不需要顯示地釋放資源。
②:對象所需的資源在生命周期內(nèi)始終保持有效。

所托管的資源,隨對象的創(chuàng)建而獲取,隨對象的消失而消失。
也就是所謂RAII思想:資源獲取即初始化。

原理

代理了被托管的對象指針,管理對象的生命周期,即實(shí)現(xiàn)自動(dòng)釋放。
其行為類似于所托管的對象指針,原因是重載了operator->和operator*。

智能指針的模板(template)實(shí)現(xiàn)

template <class T> class SmartPtr { public:explicit SmartPtr(T* pointee) : pointee_(pointee){}~SmartPtr(){delete pointee_;}T& operator*() const{//...return *pointee_;}T* operator->() const{//...return pointee_;}private:T* pointee_;//... };

auto_ptr

auto_ptr 使用

代碼演示:

#include <iostream> #include <memory>class A { public:A(){std::cout << "A()" << std::endl; //構(gòu)造器}~A(){std::cout << "~A()" << std::endl; //析構(gòu)器}void func(){std::cout << "hahaha" << std::endl; //類內(nèi)成員函數(shù)}};void foo() {A* p = new A; //new 資源獲得:會(huì)直接調(diào)用構(gòu)造器進(jìn)行初始化。delete p; //delete 資源釋放:需要手動(dòng)釋放。//一旦申請資源過多,業(yè)務(wù)邏輯代碼比較復(fù)雜的時(shí)候,在釋放的時(shí)候就可能會(huì)漏掉。std::auto_ptr<A> pp(new A);//資源獲取即初始化。// //上面//pp(new A):括號內(nèi)部就是資源獲取,并且會(huì)直接調(diào)用pp對象的構(gòu)造器進(jìn)行初始化。//也就是new進(jìn)行資源獲取后就直接進(jìn)行初始化。 理解:資源獲取即初始化。//按照使用指針的方式使用pp->func();(*pp).func();//重點(diǎn):離開作用域,對象生命周期結(jié)束,會(huì)自動(dòng)釋放對象資源。 }int main() {foo();return 0; }

運(yùn)行結(jié)果:

我們可以看到上面使用智能指針,new申請空間之后自動(dòng)調(diào)用構(gòu)造器初始化并且在對象結(jié)束后自動(dòng)調(diào)用析構(gòu)器釋放申請的內(nèi)存空間。也就是自動(dòng)調(diào)用構(gòu)造器和析構(gòu)器。

重載函數(shù) operator-> / *語法格式

類名& operator * ()
類名 * operator->()

自實(shí)現(xiàn) auto_ptr

代碼演示:

#include <iostream> #include <memory>class A { public:A(){std::cout << "A()" << std::endl; //構(gòu)造器初始化資源}~A(){std::cout << "~A()" << std::endl; //析構(gòu)銷毀資源}void func(){std::cout << "hahaha" << std::endl; //類內(nèi)成員函數(shù)}};class myauto_ptr //管理資源A的智能指針 { public:myauto_ptr(A* ptr) //構(gòu)造器初始化資源{_ptr = ptr;}~myauto_ptr() //析構(gòu)銷毀資源{delete _ptr;}A* operator->() //->運(yùn)算符重載{return _ptr;}A & operator*() //*運(yùn)算符重載{return *_ptr;}private:A* _ptr; };void foo() {myauto_ptr sp(new A);sp->func();(*sp).func(); }int main() {foo();return 0; }

運(yùn)行結(jié)果:

上面實(shí)現(xiàn)了:
類對象包裝其他對象資源時(shí),通過NEW獲取其他對象資源,通過構(gòu)造進(jìn)行其他對象資源初始化,通過析構(gòu)在其他對象消失時(shí)進(jìn)行資源釋放。

類比上面代碼中: myauto_ptr 類對象包裝 A 類對象資源時(shí),myauto_ptr 類對象通過NEW獲取A 類對象資源,通過myauto_ptr 類對象構(gòu)造進(jìn)行 A 類對象資源初始化,通過myauto_ptr 類對象析構(gòu)在 A 類對象資源消失時(shí)進(jìn)行資源釋放。

. 運(yùn)算符不可重載。
通過重載運(yùn)算符 * 和 -> ,就可以將對象像指針一樣使用。

auto_ptr被廢棄的原因

防止兩個(gè) auto_ptr 對象擁有同一個(gè)對象(一塊內(nèi)存)。
例如:ap 與 ap2 都覺得指針 p 是歸它管。在析構(gòu)時(shí)都試圖刪除 p ,兩次刪除同一個(gè)對象的行為在C++標(biāo)準(zhǔn)中沒有定義。

代碼演示:

#include <iostream> #include <memory>int main() {int* p = new int(10);{std::auto_ptr<int> ap(p); //使用ap管理pstd::cout << *ap << std::endl;}std::auto_ptr<int> ap2(p); //使用ap2管理pstd::cout << *ap2 << std::endl;return 0; }

運(yùn)行結(jié)果:

編譯器報(bào)錯(cuò)。

作參數(shù)傳遞的時(shí),亦是會(huì)出現(xiàn)同樣的情況,兩個(gè)指針,對同一段資源產(chǎn)生了引用行為。
基本類型代碼演示:

#include <iostream> #include <memory>void func(std::auto_ptr<int> tmp_ap) {//func函數(shù)運(yùn)行結(jié)束 ap2 釋放 }int main() {std::auto_ptr<int> ap(new int(100)); //使用apstd::auto_ptr<int> ap2(ap); //使用ap2管理apfunc(ap2);//func函數(shù)運(yùn)行結(jié)束 ap再次釋放std::cout << *ap << std::endl;return 0; }

運(yùn)行結(jié)果:

自定義類類型代碼演示:

#include <iostream> #include <memory> using namespace std;class Copy { public:Copy() :_i(){cout << "Copy()" << endl;}Copy(int i) :_i(new int(i)){cout << "Copy(int i)" << endl;}Copy(const Copy& another):_i(new int(*another._i)){cout << " Copy(const Copy & another)" << endl;}~Copy() {cout << "~Copy()" << endl;}int* _i; };void func(auto_ptr<Copy> apc) {}int main(int argc, char* argv[]) {auto_ptr<Copy> apc(new Copy(10));cout << *apc->_i << endl;func(apc);cout << "==============" << endl;cout << *apc->_i << endl;return 0; }

運(yùn)行結(jié)果:

析構(gòu)發(fā)生在func(apc);運(yùn)行結(jié)果之后。
apc進(jìn)入func();就是函數(shù)內(nèi)的臨時(shí)變量,在函數(shù)運(yùn)行結(jié)束之后,對于apc進(jìn)行析構(gòu)。
main函數(shù)運(yùn)行結(jié)束時(shí),ap再次析構(gòu)編譯器就會(huì)報(bào)錯(cuò)。

不允許兩個(gè)auto_ptr指針指向相同的對象。

unique_ptr

uniqu_ptr 的使用方法基本上等同于auto_ptr, 不同之處就在于實(shí)現(xiàn)了資源的唯一。既不可以拷貝也不可以賦值,正如其名字一樣。

unique_ptr使用

代碼演示:

#include <iostream> #include <memory> using namespace std;class Copy { public:Copy() :_i(){cout << "Copy()" << endl;}Copy(int i) :_i(new int(i)){cout << "Copy(int i)" << endl;}Copy(const Copy& another):_i(new int(*another._i)){cout << " Copy(const Copy & another)" << endl;}~Copy() {cout << "~Copy()" << endl;}int* _i; };void func(unique_ptr<Copy> upc) {}int main(int argc, char* argv[]) {unique_ptr<Copy> upc(new Copy(10));cout << *upc->_i << endl;unique_ptr<Copy> upc2(upc); //編譯不過func(upc); //編譯不過return 0; }

編譯器報(bào)錯(cuò):

常用接口

生命周期隨構(gòu)造者,reset 自動(dòng)析構(gòu)再重新構(gòu)造,get 判斷是否有效、支持放在容器內(nèi);真正意義智能指針。

不論是臨時(shí)變量指針、類成員指針變量…90%的指針都應(yīng)該用這個(gè)。

代碼演示:

#include <iostream> #include <memory> using namespace std;class Copy { public:Copy() :_i(){cout << "Copy()" << this << endl;}Copy(int i) :_i(new int(i)){cout << "Copy(int i)" << this << endl;}Copy(const Copy & another) :_i(new int(*another._i)){cout << " Copy(const Copy & another)" << this << endl;}~Copy() {cout << "~Copy()" << this << endl;}void dis(){cout << *_i << endl;}int* _i; };void func(unique_ptr<Copy> upc) {}int main(int argc, char* argv[]) {{unique_ptr<Copy> up;unique_ptr<Copy> up1(new Copy);if (!up) //沒有托管資源時(shí)為真{cout << "no resource" << endl;}else{cout << "has resource" << endl;}if (!up1) //托管資源時(shí)為假{cout << "no resource" << endl;}else{cout << "has resource" << endl;}cout << up1.get() << endl;//獲取所托管資源的指針Copy * p = up1.release(); //up1 release 而不是 up1 所托管的資源releasedelete p;//up1.release(); 會(huì)返回托管資源的句柄(指針),后續(xù)自行手動(dòng)管理//理解為up1中途放棄托管,所以對象結(jié)束生命周期不會(huì)自動(dòng)析構(gòu),那么需要手動(dòng)釋放對象cout << "=====================" << endl;}cout << "+++++++++++++++++++++" << endl;{unique_ptr<Copy> up2(new Copy(99));//up2.reset(); //重置, 重置之后直接調(diào)用析構(gòu)釋放資源up2.reset(new Copy(99));//重置, 重置之后調(diào)用析構(gòu)釋放舊資源,托管新資源cout << "*********************" << endl;}cout << "-------------------" << endl;unique_ptr<Copy> up3(new Copy); unique_ptr<Copy> up4 = move(up3); //支持move up4代替up3托管了up3資源,up3指針指向?yàn)閚ullptr//資源轉(zhuǎn)移cout << "" << endl;cout << up3.get() << endl;//獲取所托管資源的指針cout << up4.get() << endl;//獲取所托管資源的指針return 0; }

運(yùn)行結(jié)果:

shared_ptr

原理

unique_ptr 解決了auto_ptr 中引用同一個(gè)對象的問題,方式就是不可引用同一個(gè)對象。

shared_ptr 解決了auto_ptr 中引用同一個(gè)對象共同擁有一個(gè)資源,但不會(huì)重析構(gòu)的問題。
shared_ptr 原理是在內(nèi)部保持一個(gè)引用計(jì)數(shù),并且僅當(dāng)引用計(jì)數(shù)為0才能被刪除。

不可以用數(shù)組。

常用接口

可以有多個(gè)持有者的共享指針,即所謂引用計(jì)數(shù)型指針,直到最后一個(gè)持有者delete釋放時(shí),其指向的資源才會(huì)真正被釋放。

典型應(yīng)用案例:
如對同一個(gè)全局無鎖隊(duì)列對象由shared_ptr 封裝,多線程的多個(gè)持有者均持有對其的引用。直到全部線程都釋放掉對其的引用時(shí),該無鎖隊(duì)列對象才會(huì)被最終銷毀。

shared_ptr 適合用于管理“全局動(dòng)態(tài)資源”。

代碼演示:

#include <iostream> #include <memory> using namespace std;int main() {shared_ptr<int> sp1 (new int(666));cout << *sp1 << endl;cout << "cout:" << sp1.use_count() << endl;//1{shared_ptr<int> sp2(sp1);cout << *sp2 << endl;cout << "cout:" << sp1.use_count() << endl;//2cout << "cout:" << sp2.use_count() << endl;//2}cout << "cout:" << sp1.use_count() << endl;//1shared_ptr<int> sp3(sp1);cout << *sp3 << endl;cout << "cout:" << sp3.use_count() << endl;//2return 0; }

運(yùn)行結(jié)果:

代碼演示:

#include <iostream> #include <memory> using namespace std;class Copy { public:Copy() :_i(){cout << "Copy()" << this << endl;}Copy(int i) :_i(new int(i)){cout << "Copy(int i)" << this << endl;}Copy(const Copy & another) :_i(new int(*another._i)){cout << " Copy(const Copy & another)" << this << endl;}~Copy() {cout << "~Copy()" << this << endl;}void dis(){cout << *_i << endl;}int* _i; };void func(shared_ptr<Copy> upc) {cout << "func cout:" << upc.use_count() << endl;//3upc.reset();cout << "func cout:" << upc.use_count() << endl;//0 }int main(int argc, char* argv[]) {shared_ptr<Copy> sp1 (new Copy);cout << "cout:" << sp1.use_count() << endl;//1sp1.reset();//釋放資源//sp1.reset();//釋放資源 引用計(jì)數(shù)為0后,多次reset引用計(jì)數(shù)仍然為0。//sp1.reset();//釋放資源 引用計(jì)數(shù)為0后,多次reset引用計(jì)數(shù)仍然為0。cout << "cout:" << sp1.use_count() << endl;//0cout << "++++++++++" << endl;shared_ptr<Copy> sp2(new Copy);shared_ptr<Copy> sp3(sp2);shared_ptr<Copy> sp4(sp3);//cout << "cout:" << sp2.use_count() << endl;//3//sp2.reset(); sp2.reset(); sp2.reset(); //sp2釋放三次//cout << "cout:" << sp3.use_count() << endl;//2//重要:reset操作只管理自己身上的引用。cout << "cout:" << sp2.use_count() << endl;//3sp2.reset(); sp3.reset(); sp4.reset(); //資源的引用釋放三次cout << "cout:" << sp2.use_count() << endl;//0cout << "----------" << endl;shared_ptr<Copy> sp5(new Copy);cout << "cout:" << sp5.use_count() << endl;//1{shared_ptr<Copy> sp6(sp5);cout << "cout:" << sp5.use_count() << endl;//2cout << "cout:" << sp6.use_count() << endl;//2cout << "==========" << endl;}cout << "cout:" << sp5.use_count() << endl;//1cout << "**********" << endl;shared_ptr<Copy> sp7(sp5);cout << "cout:" << sp5.use_count() << endl;//2cout << "cout:" << sp7.use_count() << endl;//2func(sp7);cout << "cout:" << sp7.use_count() << endl;//2cout << "//" << endl;if (sp7.unique())cout << "s7 unique\n" << endl;elsecout << "s7 not unique\n" << endl;sp7.reset();cout << "cout:" << sp7.use_count() << endl;//0cout << "cout:" << sp5.use_count() << endl;//1if (sp5.unique())cout << "sp5 unique\n" << endl;elsecout << "sp5 not unique\n" << endl;return 0; }

運(yùn)行結(jié)果:

移動(dòng)和傳遞引用

代碼演示:

#include <iostream> #include <memory> using namespace std;class Copy { public:Copy() :_i(){cout << "Copy()" << this << endl;}Copy(int i) :_i(new int(i)){cout << "Copy(int i)" << this << endl;}Copy(const Copy & another) :_i(new int(*another._i)){cout << " Copy(const Copy & another)" << this << endl;}~Copy() {cout << "~Copy()" << this << endl;}void dis(){cout << *_i << endl;}int* _i; };void func(shared_ptr<Copy> & sp) {cout << "func.use_count:" << sp.use_count() << endl;//1 }int main(int argc, char* argv[]) {//moveshared_ptr<Copy> sp2(new Copy);shared_ptr<Copy> sp3(sp2);shared_ptr<Copy> sp4(sp3);cout << "sp2.use_count:" << sp2.use_count() << endl;//3shared_ptr<Copy> spm = std::move(sp2); cout << "spm.use_count:" << spm.use_count() << endl;//3cout << "sp3.use_count:" << sp3.use_count() << endl;//3cout << "sp4.use_count:" << sp4.use_count() << endl;//3//移動(dòng)不會(huì)導(dǎo)致引用計(jì)數(shù)增加。shared_ptr<Copy> sp5(new Copy);cout << "sp5.use_count:" << sp5.use_count() << endl;//1func(sp5);cout << "sp5.use_count:" << sp5.use_count() << endl;//1//傳遞shared_ptr的引用不會(huì)使引用計(jì)數(shù)+1return 0; }

運(yùn)行結(jié)果:

小結(jié)

unique_ptr可用于托管堆內(nèi)存數(shù)組。(官方僅支持unique_ptr)

代碼演示:

#include <iostream> #include <memory>using namespace std;class A { public:A(){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}void dis(){cout << "A::void dis()" << endl;} };int main() {unique_ptr<int[]> up(new int[5]{ 1,2,3,4 });for (int i = 0; i < 5; i++)cout << up[i] << endl;unique_ptr<A[]> up2(new A[5]);for (int i = 0; i < 5; i++)up2[i].dis();return 0; }

運(yùn)行結(jié)果:

shared_ptr不可用于托管堆內(nèi)存數(shù)組。(官方不支持)

總結(jié)

以上是生活随笔為你收集整理的C++智能指针详解【C++智能指针】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。