C++中的auto_ptr智能指標的作用及使用方法詳解_C 語言

來源:互聯網
上載者:User

智能指標(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 數組。

該類型在標頭檔memory中,在程式的開通通過 #include<memory> 匯入,接下來講解該智能指標的作用和使用。

使用方法:

  auto_ptr<type> ptr(new type()); 這是該指標的定義形式,其中 type 是指標指向的類型,ptr 是該指標的名稱。

  比如該type 是int,具體定義如下:

  auto_ptr<int> ptr(new int(4));

  比如該type 是map<int,vector<int> >,具體定義如下:

  auto_ptr<map<int,vector<int> > > ptr(new map<int,vector<int> > ());

  當然可以先定義,後賦值,如下所示:

  auto_ptr<map<int,int> > ptr;
  ptr = auto_ptr<map<int,int> >(new map<int,int> ());

作用1:保證一個對象在某個時間只能被一個該種類型的智能指標所指向,就是通常所說的對象所有權。

作用2:對指向的對象自動釋放的作用,詳情看如下代碼。

程式碼片段一:

#include <iostream>#include <string.h>#include <memory>#include <string>#include <Windows.h>#include <map>#include <ctime>#include <vector>using namespace std;#define MAXN 20000000class test_ptr{public:map<int,int> *p;test_ptr(){p = new map<int,int>();for(int i = 0;i<MAXN;i++)p->insert(make_pair(i,i));}};int main(int argc,char *argv[]){for(int i = 0;i<100;i++){Sleep(1000);cout << i << endl; // 輸出 建立次數test_ptr * tmp = new test_ptr();}system("pause");return 0;} 


在某些情況下,可能我們就會寫出上面的代碼來,通過運行會發現存在記憶體溢出。對於一些經驗老道的程式員可能會作如下改寫:

程式碼片段二:

#include <iostream>#include <string.h>#include <memory>#include <string>#include <Windows.h>#include <map>#include <ctime>#include <vector>using namespace std;#define MAXN 20000000class test_ptr{public:map<int,int> *p;test_ptr(){//p = auto_ptr<map<int,int> > (new map<int,int>());p = new map<int,int>();for(int i = 0;i<MAXN;i++)p->insert(make_pair(i,i));}~test_ptr(){delete p;}};int main(int argc,char *argv[]){for(int i = 0;i<100;i++){Sleep(1000);cout << i << endl; test_ptr * tmp = new test_ptr();}system("pause");return 0;} 

在test_ptr 類中的解構函式中添加記憶體釋放代碼,但是在main函數中,定義的局部指標,當局部指標失效時並不會自動調用解構函式,在這種情況下也會導致記憶體流失問題。當然,如果細心的程式員可以在 test_ptr * tmp = new test_ptr() 後面加上一句 delete tmp ,這樣也能夠釋放記憶體,不會出現記憶體流失問題。但是在某些情況下,很容易漏寫,為瞭解決此問題,auto_ptr 就能發揮作用了。

程式碼片段三:

#include <iostream>#include <string.h>#include <memory>#include <string>#include <Windows.h>#include <map>#include <ctime>#include <vector>using namespace std;#define MAXN 20000000class test_ptr{public:map<int,int> *p;test_ptr(){p = new map<int,int>();for(int i = 0;i<MAXN;i++)p->insert(make_pair(i,i));}~test_ptr(){delete p;}};int main(int argc,char *argv[]){for(int i = 0;i<100;i++){Sleep(1000);cout << i << endl; //輸出建立次數auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());}system("pause");return 0;} 

在main函數中,建立test_ptr類型指標時,該指標是auto_ptr 類型的智能指標,當智能指標失效時,會自動調用該類的解構函式。所以這種寫法可以不再顯示調用delete 語句了。但是該智能指標也只是保證調用類的解構函式,如果解構函式並沒有釋放類中聲明的變數,那該怎麼辦。

程式碼片段四:

#include <iostream>#include <string.h>#include <memory>#include <string>#include <Windows.h>#include <map>#include <ctime>#include <vector>using namespace std;#define MAXN 20000000class test_ptr{public://auto_ptr<map<int,int> > p;map<int,int> *p;test_ptr(){//p = auto_ptr<map<int,int> > (new map<int,int>());p = new map<int,int>();for(int i = 0;i<MAXN;i++)p->insert(make_pair(i,i));}/*~test_ptr(){delete p;}*/};int main(int argc,char *argv[]){for(int i = 0;i<100;i++){Sleep(1000);cout << i << endl; //輸出建立次數auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());}system("pause");return 0;}

在這種情況下,還是會出現記憶體流失問題,為瞭解決該問題,對類中聲明的指標也是需要聲明為auto_ptr類型。

程式碼片段五:

#include <iostream>#include <string.h>#include <memory>#include <string>#include <Windows.h>#include <map>#include <ctime>#include <vector>using namespace std;#define MAXN 20000000class test_ptr{public:auto_ptr<map<int,int> > p;test_ptr(){p = auto_ptr<map<int,int> > (new map<int,int>());for(int i = 0;i<MAXN;i++)p->insert(make_pair(i,i));}};int main(int argc,char *argv[]){for(int i = 0;i<100;i++){Sleep(1000);cout << i << endl; //輸出建立次數auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());}system("pause");return 0;}

這樣就不用顯示定義類的解構函式,不用在外部顯示調用delete函數,當然如果儘早調用delete函數也是可以的,儘早釋放記憶體也比該指標失效再釋放好一些,這些就是為了防止忘記調用。

通過如上分析:可以得出如下結論。

1 定義了智能指標,當智能指標失效時會自動調用類的解構函式。

2 在 類中定義的智能指標,不必在解構函式中顯示的delete,當外部調用該類的解構函式時,會自動釋放該智能指標指向的對象,釋放記憶體。

3 如果類中定義的是智能指標,但是外部沒有觸發類中的解構函式調用,該智能指標指向的對象還是不能釋放。

auto_ptr 智能指標的bug

auto_ptr 智能指標在c++ 11 標準中已經被拋棄,被拋棄的原因就是因為該bug。前面也提到過,一個對象只能被一個智能指標所引用,這樣就會導致一個賦值問題。看如下代碼

程式碼片段六:

#include <iostream>#include <string.h>#include <memory>#include <set>using namespace std;#define MAXN 20000000void pri(auto_ptr<set<int> > p){set<int>::iterator ite = p->begin();for(;ite!=p->end();ite++){cout << *ite << endl;}}int main(int argc,char *argv[]){auto_ptr<set<int> > ptr(new set<int> ());for(int i = 0;i< 3;i++){int a;cin >> a;ptr->insert(a);}pri(ptr);pri(ptr);system("pause");return 0;}

初看這代碼沒什麼問題,不過運行程式會崩潰。這就是該智能指標最大的bug, 在程式32行 調用pri(ptr) ,程式到這並沒什麼問題,但是第二次調用pri(ptr) 時程式就會崩潰。原因就是前面講過,一個對象智能被一個智能指標所指向,在第一次調用pri()函數時,為了保證這一原則,當把ptr指標傳入pri函數時,程式內部就把ptr置為空白,所以到第二次調用時,就會出現崩潰的情況。對於這種情況的解決之道就是使用shared_ptr 指標(該指標的原理是通過引用計數器來實現的)。

如果要使用shared_ptr 智能指標,需要安裝boost庫,該庫還包括許多其他功能。有興趣的可以嘗試以下,該類中的智能指標還是比較好用。也不存在很多其他bug。

以上所述是小編給大家介紹的C++中的auto_ptr智能指標執行個體詳解,希望對大家有所協助,如果大家有任何疑問請給我留言,小編會及時回複大家的。在此也非常感謝大家對雲棲社區網站的支援!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.