C++中的auto_ptr智能指針的作用及使用方法詳解
智能指針(auto_ptr) 這個名字聽起來很酷是不是?其實auto_ptr 只是C++標(biāo)準(zhǔn)庫提供的一個類模板,它與傳統(tǒng)的new/delete控制內(nèi)存相比有一定優(yōu)勢,但也有其局限。本文總結(jié)的8個問題足以涵蓋auto_ptr的大部分內(nèi)容。
auto_ptr是什么?
auto_ptr 是C++標(biāo)準(zhǔn)庫提供的類模板,auto_ptr對象通過初始化指向由new創(chuàng)建的動態(tài)內(nèi)存,它是這塊內(nèi)存的擁有者,一塊內(nèi)存不能同時被分給兩個擁有者。當(dāng)auto_ptr對象生命周期結(jié)束時,其析構(gòu)函數(shù)會將auto_ptr對象擁有的動態(tài)內(nèi)存自動釋放。即使發(fā)生異常,通過異常的棧展開過程也能將動態(tài)內(nèi)存釋放。auto_ptr不支持new 數(shù)組。
該類型在頭文件memory中,在程序的開通通過 #include<memory> 導(dǎo)入,接下來講解該智能指針的作用和使用。
使用方法:
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> > ());
當(dāng)然可以先定義,后賦值,如下所示:
auto_ptr<map<int,int> > ptr;
ptr = auto_ptr<map<int,int> >(new map<int,int> ());
作用1:保證一個對象在某個時間只能被一個該種類型的智能指針?biāo)赶颍褪峭ǔKf的對象所有權(quán)。
作用2:對指向的對象自動釋放的作用,詳情看如下代碼。
代碼片段一:
#include <iostream> #include <string.h> #include <memory> #include <string> #include <Windows.h> #include <map> #include <ctime> #include <vector> using namespace std;#define MAXN 20000000 class 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; // 輸出 創(chuàng)建次數(shù) test_ptr * tmp = new test_ptr(); } system("pause"); return 0; }
在某些情況下,可能我們就會寫出上面的代碼來,通過運行會發(fā)現(xiàn)存在內(nèi)存溢出。對于一些經(jīng)驗老道的程序員可能會作如下改寫:
代碼片段二:
#include <iostream> #include <string.h> #include <memory> #include <string> #include <Windows.h> #include <map> #include <ctime> #include <vector> using namespace std; #define MAXN 20000000 class 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 類中的析構(gòu)函數(shù)中添加內(nèi)存釋放代碼,但是在main函數(shù)中,定義的局部指針,當(dāng)局部指針失效時并不會自動調(diào)用析構(gòu)函數(shù),在這種情況下也會導(dǎo)致內(nèi)存泄漏問題。當(dāng)然,如果細心的程序員可以在 test_ptr * tmp = new test_ptr() 后面加上一句 delete tmp ,這樣也能夠釋放內(nèi)存,不會出現(xiàn)內(nèi)存泄漏問題。但是在某些情況下,很容易漏寫,為了解決此問題,auto_ptr 就能發(fā)揮作用了。
代碼片段三:
#include <iostream> #include <string.h> #include <memory> #include <string> #include <Windows.h> #include <map> #include <ctime> #include <vector> using namespace std; #define MAXN 20000000 class 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; //輸出創(chuàng)建次數(shù) auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr()); } system("pause"); return 0; }
在main函數(shù)中,創(chuàng)建test_ptr類型指針時,該指針是auto_ptr 類型的智能指針,當(dāng)智能指針失效時,會自動調(diào)用該類的析構(gòu)函數(shù)。所以這種寫法可以不再顯示調(diào)用delete 語句了。但是該智能指針也只是保證調(diào)用類的析構(gòu)函數(shù),如果析構(gòu)函數(shù)并沒有釋放類中聲明的變量,那該怎么辦。
代碼片段四:
#include <iostream> #include <string.h> #include <memory> #include <string> #include <Windows.h> #include <map> #include <ctime> #include <vector> using namespace std; #define MAXN 20000000 class 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; //輸出創(chuàng)建次數(shù) auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr()); } system("pause"); return 0; }
在這種情況下,還是會出現(xiàn)內(nèi)存泄漏問題,為了解決該問題,對類中聲明的指針也是需要聲明為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 20000000 class 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; //輸出創(chuàng)建次數(shù) auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr()); } system("pause"); return 0; }
這樣就不用顯示定義類的析構(gòu)函數(shù),不用在外部顯示調(diào)用delete函數(shù),當(dāng)然如果盡早調(diào)用delete函數(shù)也是可以的,盡早釋放內(nèi)存也比該指針失效再釋放好一些,這些就是為了防止忘記調(diào)用。
通過如上分析:可以得出如下結(jié)論。
1 定義了智能指針,當(dāng)智能指針失效時會自動調(diào)用類的析構(gòu)函數(shù)。
2 在 類中定義的智能指針,不必在析構(gòu)函數(shù)中顯示的delete,當(dāng)外部調(diào)用該類的析構(gòu)函數(shù)時,會自動釋放該智能指針指向的對象,釋放內(nèi)存。
3 如果類中定義的是智能指針,但是外部沒有觸發(fā)類中的析構(gòu)函數(shù)調(diào)用,該智能指針指向的對象還是不能釋放。
auto_ptr 智能指針的bug
auto_ptr 智能指針在c++ 11 標(biāo)準(zhǔn)中已經(jīng)被拋棄,被拋棄的原因就是因為該bug。前面也提到過,一個對象只能被一個智能指針?biāo)?,這樣就會導(dǎo)致一個賦值問題。看如下代碼
代碼片段六:
#include <iostream> #include <string.h> #include <memory> #include <set> using namespace std; #define MAXN 20000000 void 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行 調(diào)用pri(ptr) ,程序到這并沒什么問題,但是第二次調(diào)用pri(ptr) 時程序就會崩潰。原因就是前面講過,一個對象智能被一個智能指針?biāo)赶?,在第一次調(diào)用pri()函數(shù)時,為了保證這一原則,當(dāng)把ptr指針傳入pri函數(shù)時,程序內(nèi)部就把ptr置為空,所以到第二次調(diào)用時,就會出現(xiàn)崩潰的情況。對于這種情況的解決之道就是使用shared_ptr 指針(該指針的原理是通過引用計數(shù)器來實現(xiàn)的)。
如果要使用shared_ptr 智能指針,需要安裝boost庫,該庫還包括許多其他功能。有興趣的可以嘗試以下,該類中的智能指針還是比較好用。也不存在很多其他bug。
以上所述是小編給大家介紹的C++中的auto_ptr智能指針實例詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
C語言用函數(shù)實現(xiàn)電話簿管理系統(tǒng)
這篇文章主要為大家詳細介紹了C語言用函數(shù)實現(xiàn)電話簿管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12C++學(xué)習(xí)之如何進行內(nèi)存資源管理
與java、golang等自帶垃圾回收機制的語言不同,C++并不會自動回收內(nèi)存,這往往會導(dǎo)致內(nèi)存泄漏和內(nèi)存溢出等問題,所以掌握C++中的內(nèi)存管理技巧和工具是非常重要的,本文就來和大家詳細講講2023-05-05C語言MFC導(dǎo)出dll回調(diào)函數(shù)方法詳解
這篇文章主要為大家介紹了C語言MFC導(dǎo)出dll回調(diào)函數(shù)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11C語言菜鳥基礎(chǔ)教程之單精度浮點數(shù)與雙精度浮點數(shù)
在C語言中,單精度浮點數(shù)(float)和雙精度浮點數(shù)(double)類型都是用來儲存實數(shù)的,雙精度是用記憶較多,有效數(shù)字較多,數(shù)值范圍較大。2017-10-10c語言中malloc、realloc與calloc 的區(qū)別以及聯(lián)系
以下是對c語言中的malloc函數(shù),realloc函數(shù)與calloc函數(shù)的區(qū)別以及它們之間的聯(lián)系進行了介紹,需要的朋友可以過來參考下2013-08-08