提到指針,咱們就會想到指針的高效,固然,濫用指針也會爲咱們帶來許多的潛在bug。
提到指針,咱們就會想到內存泄漏。好比,使用指針後忘記釋放,長此以往,堆空間就會所有使用完,那麼會帶來很大的危害。再好比,兩個指針指向同一片內存區域,咱們對同一片區域進行了屢次釋放,一樣會形成內存泄漏。
爲了方便你們的理解,咱們先來模擬一下,使用指針卻忘記釋放帶來的危害。首先,咱們要定義一個類。此次,仍是定義女友類吧(以前寫過一篇《細說C++的友元》用的就是女友類,此次還用這個吧,方便說明問題,更況且咱們這羣碼畜怎麼會有女友呢,沒有女友只能本身建立了,哈哈哈哈)。
女生都喜歡自拍,尤爲是漂亮的女生。因此,女生會有不少照片,對吧。那麼,咱們建立的這個女友類,就讓她有照片吧。固然了,你女友的照片確定不會隨便給別人的吧,因此要把picutre這個變量聲明爲private類型。既然,女生喜歡自拍,而且發朋友圈,也就是說,其餘人雖然得不到她的照片,卻能夠經過她的朋友圈看到她的自拍,也就意味着咱們能夠經過一個public函數訪問picture這個變量。那麼,咱們如今來寫代碼。ios
class Girlfriend{ private: int pictures; public: Girlfriend ( int i ){ cout << "Girlfriend ( int i ) " << endl; /*這句代碼是不須要的, 寫在這裏只是爲了後期可以方便咱們觀察 */ this->pictures = i; } int getPic ( void ){ return this->pictures; } ~Girlfriend (){ cout << "~Girlfriend() " << endl; /*這句代碼是不須要的, 寫在這裏只是方便咱們觀察 */ } };
接着,咱們來寫一個主函數,來使用這個女友類。ide
int main ( int argc, char** argv ){ Girlfriend* Alice = new Girlfriend( 100 ); cout << "my girlfriend's pictures are " << mp->getPic() << endl; system ( "pause" ); return 0; }
運行結果:
咱們在主函數中作了什麼事情呢?咱們經過指針動態建立了一個對象,而且,我建立的這個女友Alice有100張照片。看到這裏,不少人就會想,指針危險嗎?好像沒什麼危險啊。不是使用正常嗎,看到程序運行結果,程序不是完美的執行了嘛,好像也沒什麼。
首先,咱們建立的這個指針Alice沒有去釋放,僅僅建立了一個,危害不大,可是多了以後呢。那好比,咱們如今再來寫一個主函數。函數
int main ( int argc, char** argv ){ Girlfriend* Alice = new Girlfriend( 100 ); Girlfriend* Lisa = new Girlfriend( 200 ); cout << "my girlfriend Alice's pictures are " << Alice->getPic() << endl; cout << "my girlfriend Lisa's pictures are " << Lisa->getPic() << endl; system ( "pause" ); return 0; }
運行結果:
咱們先拋開指針不談。咱們就來談談女友。假如Alice是你女友,你手機裏有她的100張照片,後來大家由於一些事情產生了矛盾分手了,因而你交了另一個女友Lisa。有一次,Lisa翻你的手機,發現你居然有100張前女朋友照片,她什麼感覺,估計要瘋了,你說後果嚴不嚴重,因此,趁你的現女朋友沒發現以前,趕忙把前女朋友照片給刪了,趕忙把前女朋友照片釋放掉,否則,後果……
如今,迴歸正題,咱們使用指針建立對象,一個,兩個,都沒問題,那若是多了呢?100個,1000個,10000個,那內存還能受的了嗎?因此,用完指針以後必定要釋放指針。
可是,咱們是人啊,不是機器,總會有遺忘的時候,那麼咱們有沒有辦法在指針使用完畢後,它本身釋放呢?當有了這個需求後,咱們就要開始思考解決辦法了。很快,咱們就有了解決方案:經過類對象模擬指針。指針有兩個運算符,一個是->,另外一個是星號,只要在類內重載這兩個操做符就好了。那麼,這個類的成員變量是什麼呢?就是一個指針。經過類來模擬指針的,這就是智能指針了。如今,咱們先來寫一個簡陋版的。測試
class SmartPointer{ private: Girlfriend* sp; public: SmartPointer ( Girlfriend* p = NULL ){ sp = p; } Girlfriend* operator -> (){ return sp; } Girlfriend& operator * (){ return *sp; } ~SmartPointer (){ delete sp; cout << "~SmartPointer() " << endl; /*這句代碼徹底不必, 寫在這裏只是便於咱們觀察 */ } }
咱們在這個智能指針類中,重載指針了指針的兩個運算符。經過這樣作,咱們解決了使用完畢指針後自動釋放的問題。那麼,還有一個問題,若是兩個指針指向同一片區域,這樣在釋放指針時也會形成內存泄漏,由於同一片區域被釋放兩次。這個問題怎麼解決呢?經過重載拷貝構造函數和賦值操做符。咱們如今類內實現拷貝構造函數。this
SmartPointer ( const SmartPointer& obj ){ sp = obj.sp; const_cast<SmartPointer&>(obj).sp = NULL; }
咱們實現了拷貝構造函數,由於同一片區域只能有一個指針指向,因此,咱們在把obj指向的地址賦給sp後,要將obj的sp賦值爲NULL。這裏用到了一個強制類型轉換。
如今,咱們要在類內實現重載賦值操做符。spa
SmartPointer& operator = ( const SmartPointer& obj ){ if ( this != &obj ){ delete sp; sp = obj.sp; obj.sp = NULL; } return *this; }
到這裏爲止,咱們就把智能指針類實現完畢了。同時,使用智能指針還能夠避免指針比較或加減運算,由於這些運算會形成指針越界帶來的bug。好了,咱們看一下,運行結果,符不符合咱們的預期。
哇,很是符合。指針使用完畢後完美釋放。
下面是完整代碼:指針
#include <iostream> #include <string> using namespace std; class Girlfriend{ private: int pictures; public: Girlfriend ( int i ){ this->pictures = i; cout << "Girlfriend ( int i )" << endl; } int getPic ( void ){ return this->pictures; } ~Girlfriend (){ cout << "~Girlfriend ()" << endl; } }; class SmartPointer{ private: Girlfriend* sp; public: SmartPointer ( Girlfriend* p = NULL ){ sp = p; cout << "SmartPointer ( Girlfriend* p = NULL )" << endl; } Girlfriend* operator -> (){ return sp; } Girlfriend& operator * (){ return *sp; } SmartPointer ( const SmartPointer& obj ){ sp = obj.sp; const_cast<SmartPointer&>(obj).sp = NULL; } SmartPointer& operator = ( const SmartPointer& obj ){ if ( this != &obj ){ delete sp; sp = obj.sp; const_cast<SmartPointer&>(obj).sp = NULL; } return *this; } bool isnull (){ return ( sp == NULL ); } ~SmartPointer (){ cout << "~SmartPointer()" << endl; delete sp; } }; int main ( int argc, char** argv ){ SmartPointer Alice = new Girlfriend( 100 ); SmartPointer Lisa = new Girlfriend( 200 ); cout << "my girlfriend Alice's pictures are " << Alice->getPic() << endl; cout << "my girlfriend Lisa's pictures are " << Lisa->getPic() << endl; system ( "pause" ); return 0; }
後記:
這篇文章寫完也是花了我兩個小時了,這其中的代碼都是通過我本身電腦測試的。雖然寫這篇文章只花了我兩個小時,可是,我在寫這篇文章以前就已經開始在構思了,該如何寫,才能作到通俗易懂。看來真的,想寫好一篇文章仍是比較困難的,畢竟要把本身學會的東西,經過語言文字描述出來,仍是不容易的。以前寫的一篇《細說C++的友元》上了博客的推薦,這裏很是感謝51cto的小編。由於,那篇文章的緣故,我全力以赴的寫了這篇文章。
但願看完的小夥伴可以學到些知識,若是以爲我哪裏講解的有誤,也能夠在評論中指出,或者哪裏有不懂的地方,也能夠在評論中留言,若是有空,咱們能夠探討下。
同時,感謝51cto的小夥伴們,大佬們花時間耐着性子看完了這篇文章,謝謝,謝謝大家!
最後,固然是但願,看完的小夥伴們,有所收穫後點個贊,表示支持。謝謝!code
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------歡迎打賞!哈哈哈哈!
對象