c++詳解【智能指針】

智能指針?是一個指針嗎?這里給大家說的是,它不是一個指針,但它模擬了指針所具有的功能。那么,為什么要有智能指針的引入呢?看看下面的例子吧~

void FunTest()
{int *p = new int[10];FILE *pFile = fopen("1.txt","r");if(pFile == NULL){return;}if(p){delete[] p;p = NULL;}
}
在c++動態內存分配空間時,是由用戶自己維護的,所以當new出來空間后,必須由用戶手動釋放。再看看上面的這個代碼,有什么問題呢?顯然的,當1.txt這個文件不存在時,pFile就為空,這就使后面釋放p的語句沒有執行,導致內存泄漏。那么怎么解決這類問題呢?

這就引入了我們重要的智能指針,所謂智能指針就是智能化的管理動態開辟的資源的釋放工作。

1、模擬實現auto_ptr

template<typename T>
class AutoPtr
{
public:AutoPtr(T* p):_p(new T(1)){cout<<"AutoPtr()"<<endl;_p = p;}AutoPtr(AutoPtr& ap):_p(ap._p){cout<<"AutoPtr(AutoPtr& ap)"<<endl;ap._p = NULL;}AutoPtr<T>& operator=(AutoPtr& ap){cout<<"AutoPtr<T>& operator=(AutoPtr& ap)"<<endl;if(this != &ap){delete _p;_a = ap._p;ap._p = NULL;}}~AutoPtr(){cout<<"~AutoPtr()"<<endl;if (_p){delete _p;_p = NULL;}}
public:T& operator*(){return *_p;}T* operator->(){return _p;}
private:T *_p;
};void FunTest()
{AutoPtr<int> ap = new int;AutoPtr<int> ap1(ap);*ap1 =  10;*(ap1.operator->()) = 20;
}
int main()
{FunTest();return 0;
}

智能指針AutoPtr的特點是:只可以管理一個對象,看一下監視窗口:



這樣就會導致資源被轉移。

當然,AutoPtr還有另一種實現方式:

template<typename T>
class AutoPtr
{
public:AutoPtr(T* p):_p(new T(1)){cout<<"AutoPtr()"<<endl;_p = p;_owner = true;}AutoPtr(AutoPtr& ap):_p(ap._p){cout<<"AutoPtr(AutoPtr& ap)"<<endl;ap._owner = false;ap._p = NULL;_owner = true;}AutoPtr<T>& operator=(AutoPtr& ap){cout<<"AutoPtr<T>& operator=(AutoPtr& ap)"<<endl;if(this != &ap){delete _p;_a = ap._p;ap._owner = false;ap._p = NULL;_owner = true;}}~AutoPtr(){cout<<"~AutoPtr()"<<endl;if (_p){delete _p;_p = NULL;_owner = false;}}
public:T& operator*(){return *_p;}T* operator->(){return _p;}
private:T *_p;bool _owner;
};void FunTest()
{AutoPtr<int> ap = new int;AutoPtr<int> ap1(ap);*ap1 =  10;*(ap1.operator->()) = 20;}int main()
{FunTest();return 0;
}

這種方式就是定義一個私有成員,用來標記當前對象的狀態,若為false,表示當前對象已不再指向任何空間,若為true,說明該對象指向申請的那塊內存。



那么,這種類型的指針有什么弊端嗎?首先,只能管理單個對象,每次只有一個對象可使用申請的空間。其次,使得資源轉移,另一個對象使用時,前一個對象將賦為空。

但是切記不要使用auto_ptr

2、模擬實現scoped_ptr

scoped_ptrauto_ptr一樣,都是管理單個對象的。它的作用是:在一個類中防止拷貝。說起防止拷貝,大家會想到把它定義為私有的,總可以了吧。其實并不可以,因為訪問私有成員或函數的方式還有將調用它的函數聲明為類的友元就ok啦。所以,在這里,我們將學到一種防拷貝的方式:只聲明不定義,且將拷貝構造和賦值運算符重載聲明為私有即可。

實現如下:

template<typename T>
class ScopedPtr
{
public:ScopedPtr(const T* p):_p(p){}~ScopedPtr(){if(_p){delete _p;_p = NULL;}}T& operator*(){return *_p;}T* operator->(){return _p;}
private:ScopedPtr(const ScopedPtr&);ScopedPtr<T>& operator=(const ScopedPtr&);
private:T* _p;
};void FunTest()
{ScopedPtr<int> sp = new int;ScopedPtr<int> sp1(sp);    //error,這樣就使用不了拷貝構造函數了ScopedPtr<int> sp1 = sp;   //error,使用不了賦值運算符重載}int main()
{FunTest();return 0;
}

scoped_ptr實現的機制體現了它的獨占性,當一個對象占用一塊空間時,其他對象將無法使用。并且解決了不讓資源轉移的問題。

注:在STL源碼庫中使用的是scoped_ptr,而在boost庫中,使用的是unique_ptr。兩個其實是一樣的。

3、模擬實現shared_ptr

前面兩個智能指針都是管理單個對象,而這個shared_ptr則是可以管理多個對象。它們之間的資源是共享的。

以下代碼是使用引用計數的方式實現資源共享。

實現代碼如下:

template<typename T>
class SharedPtr
{
public:SharedPtr(T* p = NULL):_p(p),_pCount(new int(1)){cout<<"SharedPtr(T* p = NULL)"<<endl;}SharedPtr(SharedPtr& sp):_p(sp._p),_pCount(sp._pCount){cout<<"SharedPtr(SharedPtr& sp)"<<endl;}SharedPtr<T>& operator=(const SharedPtr& sp){cout<<"SharedPtr<T>& operator=(const SharedPtr& sp)"<<endl;if(_p != sp._p){if(_p == NULL){_p = sp._p;_pCount = sp._pCount;}else if(_p && (*_pCount== 1)){delete _p;_p = sp._p;_pCount = sp._p;}else{--(*_pCount);_p = sp._p;_pCount = sp._pCount;}if(sp._p)++(*_pCount);}return *this;}~SharedPtr(){cout<<"~SharedPtr()"<<endl;if(_p && --(*_pCount) == 0){delete _p;_p = NULL;}}
public:T& operator*(){return *_p;}T* operator->(){return _p;}int UseCount(){if(_pCount != NULL)return *_pCount;return 0;}private:T *_p;int *_pCount;
};void FunTest()
{SharedPtr<int> sp = new int(1);SharedPtr<int> sp1(sp);SharedPtr<int> sp2;sp = sp1;sp2 = sp1;cout<<sp.UseCount()<<endl;cout<<sp1.UseCount()<<endl;cout<<sp2.UseCount()<<endl;
}int main()
{FunTest();return 0;
}

運行結果:



此版本雖然實現了共享,但也存在著不少問題,比如線程安全問題、循環引用問題,定置刪除器問題等。這幾個問題我們下一篇再詳細解說哦。


希望大家可以對博客提出寶貴意見,歡迎來訪哦。微笑微笑

















本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382803.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382803.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382803.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python 使用 os的 popen(‘命令’) 如果命令行輸出中 有中文亂碼, 提示 'gbk' 無法解析的錯誤 解決辦法

os.chdir(‘你的命令’) res os.popen(v.testcomman)print(tempstream.buffer.read().decode(encodingutf-8)&#xff09;

node.js async await 配合Promise對象使用

function getData(){return new Promise(function(resolve, reject){setTimeout(function(){var uname zhang;console.log(this is timeout);resolve(uname);}, 1000);}); } //await 配合 promiese 的 resolve 使用 就會真的等待 同步 async function test(){console.log(1);v…

c++【深度剖析shared_ptr】

shared_ptr解決了scoped_ptr管理單個對象的缺陷&#xff0c;且解決了防拷貝的問題。shared_ptr可以管理多個對象&#xff0c;并且實現了資源共享。 但是仍然存在一些問題&#xff0c;比如&#xff0c;我們熟悉的雙向鏈表&#xff1a; struct Node { Node(const int& value…

centos重新安裝yum

1.備份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下載新的CentOS-Base.repo 到/etc/yum.repos.d/ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo 3. yum makecache GDB的安裝 yum…

Electron 渲染進程,如何解決require is not defined的問題

mainWindow new BrowserWindow({webPreferences: {nodeIntegration: true}}) // nodeIntegration: true 加上這一句 就可以了 5.0以后默認是false

c++詳解【new和delete】

說起new和delete&#xff0c;了解過c的人應該都知道吧&#xff0c;它是用來分配內存和釋放內存的兩個操作符。與c語言中的malloc和free類似。 c語言中使用malloc/calloc/realloc/free進行動態內存分配&#xff0c;malloc/calloc/realloc用來在堆上分配空間&#xff0c;free將申…

vim 的配置文件 #vim ~/.vimrc

set hlsearch set backspace2 set nu set showmode set ruler set autoindent syntax on set smartindent set tabstop4 set shiftwidth4 set expandtab imap { {}iV

關于tornado的異步耗時操作假設

tornado 如果遇到耗時的操作&#xff0c;可不可以這樣 把耗時操作放在一個由 python進程池維護的 pool中&#xff0c; 用 webapi封裝起來&#xff0c; 然后tornado 接收客戶端請求后&#xff0c;遇到耗時操作就 與訪問另一個webapi &#xff0c; webapi去調用進程池 這種模型不…

Stack/Queue與Vector/List的聯系

Vector:(順序表【數組存儲】) 1.當申請的空間不足的時候&#xff0c;需要再次開辟一塊更大的空間&#xff0c;并把值拷過去。 2.對于尾刪和尾插是比較方便的&#xff0c;只需要改動最后一個元素即可。不會改動原有的空間。適用于多次重復的對尾部插刪。 3.順序存儲&#xff…

利用SetConsoleTextAttribute函數設置控制臺顏色

原文出處&#xff1a; https://blog.csdn.net/odaynot/article/details/7722240 混合顏色 #include <windows.h> #include <iostream> using namespace std;int main() {HANDLE hOut;hOut GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hOut,FOREG…

用棧實現后綴表達式求解問題

一、問題概述&#xff1a; 人們經常書寫的數學表達式屬于中綴表達式&#xff0c;今天要解決的是&#xff0c;后綴表達式的求解問題。 如下圖分別為舉例的中綴表達式和后綴表達式&#xff1a; 二、解決思路 我們用棧存儲后綴表達式中的數據部分&#xff0c;當遇到操作符時就取…

SetConsoleCursorPosition光標的位置控制

SetConsoleCursorPosition是一個計算機函數&#xff0c;如果用戶定義了 COORD pos&#xff0c;那么pos其實是一個結構體變量&#xff0c;其中X和Y是它的成員&#xff0c; 通過修改pos.X和pos.Y的值就可以實現光標的位置控制。 復制粘貼運行一下&#xff0c;你就明白代碼什么意…

用棧和遞歸求解迷宮問題

一、問題概述 小時候&#xff0c;我們都玩過走迷宮的游戲吧。看一下這個圖例&#xff1a; 遇到這種問題時&#xff0c;我們第一反應都會先找到迷宮的入口點&#xff0c;然后對上下左右四個方向進行尋跡&#xff0c; 檢測當前位置是否是通路&#xff0c;是否可以通過&#xff0…

exit(0) return區別

1. return是返回函數調用&#xff0c;如果返回的是main函數&#xff0c;則為退出程序。 exit是在調用處強行退出程序&#xff0c;運行一次程序就結束&#xff0c; 無論寫在那里&#xff0c;都是程序推出&#xff0c;括號里的數字0,1,-1會被寫入環境變量ERRORLEVEL&#xff0c…

electron 5.0.3版本 改動的地方

BrowserWindow.getFocusedWindow 1. BrowserWindow.getFocusedWindow getFocusedWindow 已經不是一個方法了&#xff0c; 這個簡單的問題解決了半天&#xff0c;因為我看文檔上 還是當一個方法來調用&#xff0c; 文檔沒有正確更新&#xff0c;實際上已經變成了一個屬性&#…

【c語言】棋盤游戲--三子棋

一、問題概述 大家都玩過棋盤游戲吧&#xff0c;像五子棋一樣&#xff0c;玩家或者是電腦一人下一次&#xff0c;當玩家或者是電腦的某一方先將各自的五個棋子下成一條線時&#xff0c;誰就贏&#xff0c;棋盤游戲就會結束。 當然&#xff0c;我今天要介紹的是三子棋&#xff…

【轉】淺析task_struct結構體

https://blog.csdn.net/peiyao456/article/details/54407343

electron 主進程與渲染進程 渲染進程與渲染進程 之間的通信

主進程與渲染進程之間的通信 這是渲染進程 // 渲染進程執行主進程里面的方法&#xff0c;主進程給渲染進程反饋處理結果 。 var sendreplayDomdocument.querySelector(#sendreplay); sendreplayDom.onclickfunction(){// alert(1213)//渲染進程給主進程廣播數據ipcRenderer.se…

centos升級之gcc 升級 gcc-7.3.0安裝

更新于&#xff1a;2018_7_28 安裝時間非常非常久&#xff0c;我最快一次40分鐘&#xff0c;最長一次兩個小時 cd / wget ftp.gnu.org/gnu/gcc/gcc-7.3.0/gcc-7.3.0.tar.gz tar -zxvf gcc-7.3.0.tar.gz cd gcc-7.3.0 ./contrib/download_prerequisites mkdir build cd …