自己搭建服務(wù)器做網(wǎng)站91手機(jī)用哪個(gè)瀏覽器
文章目錄
- RAII
- 一、auto_ptr
- 二、unique_ptr
- 三、shared_ptr
- shared_ptr的循環(huán)引用問(wèn)題
- 四、weak_ptr
- 總結(jié)
RAII
RAII就是將資源交給一個(gè)對(duì)象管理,這個(gè)對(duì)象能進(jìn)行正常的管理和釋放資源。
一、auto_ptr
auto_ptr的問(wèn)題是:在拷貝構(gòu)造和賦值重載時(shí),會(huì)將自己資源的管理權(quán)轉(zhuǎn)移給對(duì)方。
template<class T>
class auto_ptr
{
public:auto_ptr(T* ptr):_ptr(ptr){}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//ap3(ap1)auto_ptr(auto_ptr<T>& ap):_ptr(ap._ptr){ap._ptr = nullptr;//必須置空,否則兩個(gè)指針對(duì)象管理同一塊空間,會(huì)調(diào)用析構(gòu)兩次}operator=(auto_ptr<T>& ap){_ptr = ap._ptr;ap._ptr = nullptr;}~auto_ptr(){delete _ptr; // _ptr是指針,是內(nèi)置類型,默認(rèn)生成的析構(gòu)函數(shù)不處理//自定義類型調(diào)用它自己的析構(gòu)_ptr = nullptr;}
private:T* _ptr;
};
這個(gè)auto_ptr實(shí)際不會(huì)用,太挫了。
但面試可能要手撕,也要會(huì)。
二、unique_ptr
unique_ptr 簡(jiǎn)單粗暴地禁止了拷貝和賦值重載,那就解決了上面auto_ptr的管理權(quán)轉(zhuǎn)移問(wèn)題了。
template<class T>class unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}unique_ptr(unique_ptr<T>& up) = delete;unique_ptr<T>& operator=(unique_ptr<T>& up) = delete;~unique_ptr(){delete _ptr; // _ptr是指針,是內(nèi)置類型,默認(rèn)生成的析構(gòu)函數(shù)不處理//自定義類型調(diào)用它自己的析構(gòu)_ptr = nullptr;}private:T* _ptr;};
所以u(píng)nique_ptr就比較適用于,一個(gè)指針獨(dú)占一個(gè)資源的情況。
三、shared_ptr
shared_ptr使用了引用計(jì)數(shù)器,最開(kāi)始new對(duì)象時(shí),計(jì)數(shù)器為1。
而當(dāng)其他的同類型的指針對(duì)象也指向該對(duì)象時(shí),計(jì)數(shù)器+1。
當(dāng)有指針對(duì)象調(diào)用析構(gòu)函數(shù)時(shí),判斷計(jì)數(shù)器是否為0,如果不為0,表明我這個(gè)對(duì)象還有其他的shared_ptr在管理,不需要delete,讓計(jì)數(shù)器-1即可。
如果計(jì)數(shù)器為0,表明當(dāng)前的shared_ptr是最后一個(gè)指針對(duì)象管理資源了。就delete。
shared_ptr解決了auto_ptr的管理權(quán)轉(zhuǎn)移問(wèn)題,也解決了unique_ptr的不讓拷貝和賦值的問(wèn)題。
注意的問(wèn)題:
- 1.不能賦值給自己,否則計(jì)數(shù)器會(huì)++。
還有一個(gè)問(wèn)題:默認(rèn)的析構(gòu)函數(shù)的處理方式是delete ptr。
如果指針管理的資源是T[],或者是fopen,或者是malloc的呢?
如果還使用默認(rèn)的處理方式delete ptr,就會(huì)出現(xiàn)問(wèn)題。
資源是T[],就得用delete[] ,是fopen,就得用fclose,是malloc,就得用free。
所以在傳參的時(shí)候,就需要傳處理方法過(guò)來(lái)了。(可以傳對(duì)象的方法,可以傳lambda,可以傳包裝器。
所以就需要將析構(gòu)函數(shù),設(shè)置成一個(gè)對(duì)象/包裝器,調(diào)用的就是傳進(jìn)來(lái)的析構(gòu)方法。 - 2.實(shí)現(xiàn)賦值重載的時(shí)候,有很多細(xì)節(jié)。
-
- 不能自己給自己賦值
-
- 在把對(duì)方賦值給自己之前,需要把自己所指向的計(jì)時(shí)器減減,因?yàn)槲乙幌蚱渌挠?jì)時(shí)器了。如果減減后的計(jì)時(shí)器為0,說(shuō)明這塊資源只有我一個(gè)指針在管理,現(xiàn)在我要只想其他資源,所以我要先釋放我現(xiàn)在的資源才能去指向其他資源,否則就會(huì)出現(xiàn)內(nèi)存泄露問(wèn)題。
- 在把對(duì)方賦值給自己之前,需要把自己所指向的計(jì)時(shí)器減減,因?yàn)槲乙幌蚱渌挠?jì)時(shí)器了。如果減減后的計(jì)時(shí)器為0,說(shuō)明這塊資源只有我一個(gè)指針在管理,現(xiàn)在我要只想其他資源,所以我要先釋放我現(xiàn)在的資源才能去指向其他資源,否則就會(huì)出現(xiàn)內(nèi)存泄露問(wèn)題。
template<class T>class shared_ptr{public://1) 使用定制刪除器,解決一個(gè)當(dāng)new []時(shí),需要delete []的問(wèn)題//2) 還有 使用malloc時(shí),需要free配對(duì)//3) 使用fopen,需要fclose配對(duì)template<class D>shared_ptr(T* ptr,D del):_ptr(ptr),_pcount(new int(1)),_del(del){}//然而這里有一個(gè)問(wèn)題,模板D不是全局的,而是只針對(duì)這個(gè)構(gòu)造函數(shù)//所以應(yīng)該如何創(chuàng)建_del對(duì)象呢?//使用包裝器//function <void(T*)> _del;//因?yàn)椴还苁巧厦嫒N情況的哪一種,共同點(diǎn)都是使用的仿函數(shù)的返回值都是void,指針類型都是T*T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//sp3(sp1)shared_ptr(shared_ptr<T>& sp):_ptr(sp._ptr),_pcount(sp._pcount) //讓他們的引用計(jì)數(shù)器指針指向同一個(gè)計(jì)數(shù)器{++(*_pcount);}//sp5 = sp2shared_ptr<T>& operator=(shared_ptr<T>& sp){//不能自己賦值給自己,否則引用計(jì)數(shù)器會(huì)++//這樣判斷是可以的,只要不同的對(duì)象指向同一個(gè)資源空間,這幾個(gè)對(duì)象之間的賦值都是相當(dāng)于自己給自己賦值if(_ptr == sp._ptr) //if (_pcount == sp._pcount) //這也可以{return *this;}//賦值前,需要將之前的計(jì)數(shù)器--,如果計(jì)數(shù)器為0,就釋放資源//因?yàn)槲乙赶蚱渌Y源了,我原來(lái)的資源的計(jì)數(shù)器當(dāng)然要--if (--(*sp._pcount) == 0){_del(sp._ptr);delete sp._pcount;}_ptr = sp._ptr;_pcount = sp._pcount;++(*_pcount);return *this;}~shared_ptr(){if (--(*_pcount) == 0){_del(_ptr);delete _pcount;_pcount = nullptr;_ptr = nullptr;}}T* get() const {return _ptr;}int use_count() const {return *_pcount;}private:T* _ptr;int* _pcount;//包裝器//包裝器包裝的_del是D類型,這個(gè)D也不知道是什么類型,//包裝器可以包裝仿函數(shù),包裝對(duì)象的方法等。//如果只是普通的指針析構(gòu),那就給一個(gè)缺省。function <void(T*)> _del = [](T* ptr) {delete ptr; }; //dzt::shared_ptr<int> svr(new int); //這樣的方式,就是沒(méi)傳處理方式,那默認(rèn)就是用缺省。//dzt::shared_ptr<int> svr(new int[10],[](int* ptr){delete[] ptr};//這樣的傳參方式,就用delete[]解決};
shared_ptr的循環(huán)引用問(wèn)題
循環(huán)引用問(wèn)題是兩個(gè)節(jié)點(diǎn)的shared_ptr指針互相指向的時(shí)候,引用計(jì)數(shù)器都會(huì)+1,這就出現(xiàn)了互相的計(jì)數(shù)器都是2.在析構(gòu)時(shí),都變成1,此時(shí)就出現(xiàn)了,到底誰(shuí)先析構(gòu)的問(wèn)題。
就一直死循環(huán)了。
不過(guò),shared_ptr能解決日常生活99%的問(wèn)題,它只有一個(gè)缺點(diǎn),就是循環(huán)引用問(wèn)題。
解決辦法:weak_ptr,weak_ptr是專門(mén)解決循環(huán)引用這個(gè)問(wèn)題的。
weak_ptr沒(méi)有RAII,沒(méi)有引用計(jì)數(shù),不參與對(duì)象資源的管理和釋放,只是一個(gè)簡(jiǎn)單的訪問(wèn)資源的操作。
四、weak_ptr
template<class T>class weak_ptr{public:weak_ptr():_ptr(nullptr){}weak_ptr(T* ptr):_ptr(ptr){}//weak_ptr必須支持一個(gè)shared_ptr構(gòu)造weak_ptr的構(gòu)造函數(shù)weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){//類外面無(wú)法直接訪問(wèn)類的私有成員_ptr = sp.get();return *this;}//weak只支持訪問(wèn)資源的操作T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//weak_ptr不參與對(duì)象資源的管理和釋放,所以沒(méi)有析構(gòu)函數(shù)private:T* _ptr;};
總結(jié)
本文講述了幾個(gè)智能指針的優(yōu)缺點(diǎn)和模擬實(shí)現(xiàn)。