程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++中auto_ptr智能指針的用法詳解

C++中auto_ptr智能指針的用法詳解

編輯:關於C++

C++中auto_ptr智能指針的用法詳解。本站提示廣大學習愛好者:(C++中auto_ptr智能指針的用法詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中auto_ptr智能指針的用法詳解正文


智能指針(auto_ptr) 這個名字聽起來很酷是否是?其實auto_ptr 只是C++尺度庫供給的一個類模板,它與傳統的new/delete掌握內存比擬有必定優勢,但也有其局限。本文總結的8個成績足以涵蓋auto_ptr的年夜部門內容。

auto_ptr是甚麼?

auto_ptr 是C++尺度庫供給的類模板,auto_ptr對象經由過程初始化指向由new創立的靜態內存,它是這塊內存的具有者,一塊內存不克不及同時被分給兩個具有者。當auto_ptr對象性命周期停止時,其析構函數會將auto_ptr對象具有的靜態內存主動釋放。即便產生異常,經由過程異常的棧睜開進程也能將靜態內存釋放。auto_ptr不支撐new 數組。

C++中指針請求和釋放內存平日采取的方法是new和delete。但是尺度C++中還有一個壯大的模版類就是auto_ptr,它可以在你不消的時刻主動幫你釋放內存。上面簡略說一下用法。

<textarea cols="50" rows="15" name="code" class="cpp">

用法一: std::auto_ptr<MyClass>m_example(new MyClass());

用法二: std::auto_ptr<MyClass>m_example; m_example.reset(new MyClass());

用法三(指針的賦值操作): std::auto_ptr<MyClass>m_example1(new MyClass());

std::auto_ptr<MyClass>m_example2(new MyClass()); m_example2=m_example1;</textarea>

則C++會把m_example所指向的內存收受接管,使m_example1 的值為NULL,所以在C++中,應相對防止把auto_ptr放到容器中。即應防止以下代碼:

vector<auto_ptr<MyClass>>m_example;

當用算法對容器操作的時刻,你很難防止STL外部對容器中的元素完成賦值傳遞,如許便會使容器中多個元素被置位NULL,而這不是我們想看到的。

固然,尺度auto_ptr智能指針機制許多人都曉得,但很少應用它。這真是個遺憾,由於auto_ptr優雅地處理了C++設計和編碼中罕見的成績,准確地應用它可以生成硬朗的代碼。本文論述了若何准確應用auto_ptr來讓你的代碼加倍平安——和若何防止對auto_ptr風險但罕見的誤用,這些誤用會激發連續性發生發火、難以診斷的bug。

為何稱它為“主動”指針?auto_ptr只是浩瀚能夠的智能指針之一。很多貿易庫供給了更龐雜的智能指針,用處普遍而使人驚奇,從治理援用的數目到供給先輩的署理辦事。可以把尺度C++ auto_ptr看做智能指針的Ford Escort(elmar注:能夠指福特的一種合適家居的車型):一個簡略單純、通用的智能指針,它不包括一切的小技能,不像公用的或高機能的智能指針那末豪華,然則它可以很好的完成很多廣泛的任務,它很合適平常性的應用。

auto_ptr所做的工作,就是靜態分派對象和當對象不再須要時主動履行清算。這裡是一個簡略的代碼示例,沒有應用auto_ptr所以不平安:

<textarea cols="50" rows="15" name="code" class="cpp">// 示例1(a):原始代碼 void f() { T* pt( new T ); /*...更多的代碼...*/ delete pt; }</textarea>

我們年夜多半人天天寫相似的代碼。假如f()函數只要三行而且不會有任何不測,這麼做能夠挺好的。然則假如f()從不履行delete語句,或許是因為過早的前往,或許是因為履行函數體時拋出了異常,那末這個被分派的對象就沒有被刪除,從而我們發生了一個經典的內存洩露。

能讓示例1(a)平安的簡略方法是把指針封裝在一個“智能的”相似於指針的對象裡,這個對象具有這個指針而且能在析構時主動刪除這個指針所指的對象。由於這個智能指針可以簡略確當成一個主動的對象(這就是說,它出了感化域時會主動撲滅),所以很天然的把它稱之為“智能”指針:

<textarea cols="50" rows="15" name="code" class="cpp">// 
示例1(b):平安代碼,應用了auto_ptr void f() { auto_ptr<T> pt( new T ); /*...更多的代碼...*/ } // 酷:當pt出了感化域時析構函數被挪用,從而對象被主動刪除</textarea>

如今代碼不會洩露T類型的對象,不論這個函數是正常加入照樣拋出了異常,由於pt的析構函數老是會在出棧時被挪用,清算會主動停止。

最初,應用一個auto_ptr就像應用一個內建的指針一樣輕易,並且假如想要“撤消”資本,從新采取手動的一切權,我們只需挪用release()。

<textarea cols="50" rows="15" name="code" class="cpp">// 示例2:應用一個auto_ptr void g() { // 如今,我們有了一個分派好的對象 T* pt1 = new T; // 將一切權傳給了一個auto_ptr對象 auto_ptr<T> pt2(pt1); // 應用auto_ptr就像我們之前應用簡略指針一樣, *pt2 = 12; // 就像*pt1 = 12 pt2->SomeFunc(); // 就像pt1->SomeFunc(); // 用get()來取得指針的值 assert( pt1 == pt2.get() ); // 用release()來撤消一切權 T* pt3 = pt2.release(); // 本身刪除這個對象,由於如今沒有任何auto_ptr具有這個對象 delete pt3; } // pt2不再具有任何指針,所以不要試圖刪除它...OK,不要反復刪除 </textarea>

最初,我們可使用auto_ptr的reset()函數來重置auto_ptr使之具有另外一個對象。假如這個auto_ptr曾經具有了一個對象,那末,它會先刪除曾經具有的對象,是以挪用reset()就好像燒毀這個auto_ptr,然後新建一個並具有一個新對象:

<textarea cols="50" rows="15" name="code" class="cpp">//
示例 3:應用reset() void h() { auto_ptr<T> pt( new T(1) ); pt.reset( new T(2) ); // 刪除由"new T(1)"分派出來的第一個T } // 最初pt出了感化域,第二個T也被刪除</textarea>

auto_ptr用法:

1. 須要包括頭文件<memory>。

2. Constructor:explicit auto_ptr(X* p = 0) throw(); 將指針p交給auto_ptr對象托管。

3. Copy constructor:auto_ptr(const auto_ptr&) throw(); template<class Y> auto_ptr(const auto_ptr<Y>& a) throw(); 指針的托管權會產生轉移。

4. Destructor: ~auto_ptr(); 釋放指針p指向的空間。

5. 供給了兩個成員函數 X* get() const throw(); //前往保留的指針

6. 對象中仍保存指針 X* release() const throw(); //前往保留的指針,對象中不保存指針

auto_ptr完成症結點:

1. 應用特色“棧上對象在分開感化規模時會主動析構”。

2. 關於靜態分派的內存,其感化規模是法式員手動掌握的,這給法式員帶來了便利但也弗成防止忽視形成的內存洩露,究竟只要編譯器是最靠得住的。
3. auto_ptr經由過程在棧上構建一個對象a,對象a中wrap了靜態分派內存的指針p,一切對指針p的操作都轉為對對象a的操作。而在a的析構函數中會主動釋放p的空間,而該析構函數是編譯器主動挪用的,無需法式員費心。

多說有益,看一個最適用的例子:

<textarea cols="50" rows="15" name="code" class="cpp">#include <iostream> #include <memory> using namespace std; class TC { public: TC(){cout<<"TC()"<<endl;} ~TC(){cout<<"~TC()"<<endl;} }; void foo(bool isThrow) { auto_ptr<TC> pTC(new TC); 
// 辦法2 //TC *pTC = new TC; 
// 辦法1 try { if(isThrow) throw "haha"; } catch(const char* e) { //delete pTC; // 辦法1 throw; } //delete pTC; // 辦法1 } int main() { try { foo(true); } catch(...) { cout<<"caught"<<endl; } system("pause"); }</textarea>

1. 假如采取計劃1,那末必需斟酌到函數在因throw異常的時刻釋放所分派的內存,如許形成的成果是在每一個分支處都要很當心的手動 delete pTC;。

2. 假如采取計劃2,那就無需費心什麼時候釋放內存,不論foo()因何緣由加入, 棧上對象pTC的析構函數都將挪用,是以托管在當中的指針所指的內存必定平安釋放。
至此,智能指針的長處曾經很清楚明了了。

然則要留意應用中的一個圈套,那就是指針的托管權是會轉移的。 例如在上例中,假如 auto_ptr<TC> pTC(new TC); auto_ptr<TC> pTC1=pTC; 那末,pTC1將具有該指針,而pTC沒有了,假如再用pTC去援用,必定招致內存毛病。

要防止這個成績,可以斟酌應用采取了援用計數的智能指針,例如boost::shared_ptr等。auto_ptr不會下降法式的效力,但auto_ptr不實用於數組,auto_ptr基本弗成以年夜范圍應用。 shared_ptr也要合營weaked_ptr,不然會很輕易觸發輪回援用而永久沒法收受接管內存。 實際上,公道應用容器加智能指針,C++可以完整防止內存洩漏,效力只要眇乎小哉的降低(中型以上法式最多百分之一)。

以上所述是小編給年夜家引見的C++中auto_ptr智能指針的用法詳解,願望對年夜家有所贊助,假如年夜家有任何疑問請給我留言,小編會實時答復年夜家的。在此也異常感激年夜家對網站的支撐!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved