C++內(nèi)存管理介紹
前言;
C++繼承了C語(yǔ)言的指針,一直以來(lái)指針的一些問(wèn)題困擾著開(kāi)發(fā)人員,常見(jiàn)的指針問(wèn)題主要有:內(nèi)存泄露、野指針、訪問(wèn)越界等。值得慶幸的是C++標(biāo)準(zhǔn)委員會(huì)給我們提供了auto_ptr智能指針,后面又引入了share_ptr以及weak_ptr幫助我們正確和安全的使用指針,本文主要是介紹boost庫(kù)提供的解決方案,期望通過(guò)本文能夠給你提供一個(gè)新的天地。
1 smart_ptr概述
在實(shí)際開(kāi)發(fā)時(shí),我們會(huì)根據(jù)不同的編程場(chǎng)景申請(qǐng)不同的資源,對(duì)于這些資源的管理需要一個(gè)完善的方案,我們希望在資源釋放后,C++能夠像java,c#一樣不用去手動(dòng)的釋放資源而是由系統(tǒng)自動(dòng)對(duì)資源進(jìn)行回收。
1.1 RAII進(jìn)制
C++編程時(shí)通常使用這種方法管理資源,申請(qǐng)的資源超過(guò)生命周期后,生命的對(duì)象自動(dòng)調(diào)用析構(gòu)函數(shù)對(duì)資源進(jìn)行正確回收。如此看來(lái),似乎是完美的解決我們的問(wèn)題,至少在使用時(shí)不用手動(dòng)釋放資源。但是這種資源釋放的方法同樣存在著缺陷,如果對(duì)象是在棧上創(chuàng)建得到,那么會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),結(jié)果也是沒(méi)有問(wèn)題的,但是如果對(duì)象是通過(guò)new在堆上創(chuàng)建的呢?結(jié)果是析構(gòu)函數(shù)不能自動(dòng)被調(diào)用,同樣需要我們使用delete進(jìn)行顯示析構(gòu)。如果程序在執(zhí)行時(shí)沒(méi)有調(diào)用析構(gòu)delete進(jìn)行釋放資源,那么同樣也會(huì)存在內(nèi)存泄露的風(fēng)險(xiǎn)。
new/delete在編程時(shí)一定要遵循配對(duì)原則,且要服從誰(shuí)創(chuàng)建誰(shuí)釋放的規(guī)則,這一點(diǎn)不管是新手程序員還是有著豐富編程經(jīng)驗(yàn)的老手都要認(rèn)真對(duì)待。
1.2 智能指針
從C98開(kāi)始,C++標(biāo)準(zhǔn)委員會(huì)就給我們提供了智能指針:auto_ptr。它部分解決了資源的自動(dòng)釋放問(wèn)題。
使用方法如下:
std::auto_ptr<int> p (new int);
auto_ptr的構(gòu)造函數(shù)支持new操作符或者由對(duì)象工廠創(chuàng)建的對(duì)象指針作為參數(shù)。對(duì)象一經(jīng)創(chuàng)建就托管了原始指針,因此它可以使用get方法返回指針對(duì)象,如:
*p.get() = 100;
auto_ptr受到了大家的歡迎,越來(lái)越多的人使用這種技術(shù)解決了實(shí)際編程中大部分得到資源管理的問(wèn)題,但是,auto_ptr并不是一種非常完善的技術(shù),也沒(méi)有覆蓋到智能指針的所有領(lǐng)域,尤其是引用計(jì)數(shù)型的智能指針。同理,在使用auto_ptr的時(shí)候也要注意以下幾點(diǎn),避免auto_ptr的濫用。
- auto_ptr不能共享所有權(quán),即不要讓兩個(gè)auto_ptr指向同一個(gè)對(duì)象。
- auto_ptr不能指向數(shù)組,因?yàn)?code>auto_ptr在析構(gòu)的時(shí)候只是調(diào)用
delete。 - auto_ptr只是一種簡(jiǎn)單的智能指針,如有特殊需求,需要使用其他智能指針,比如
share_ptr。 - auto_ptr不能作為容器對(duì)象。
為了解決auto_ptr的不足,boost庫(kù)提供了多種類(lèi)之中從而完善了auto_ptr的不足。這些指針都在boost庫(kù)的頭文件中,
如下所示:
#include <boost/smart_ptr.hpp> using namespace boost;
1.3 scoped_ptr
該類(lèi)型指針和auto_ptr類(lèi)似,但是限制也更加嚴(yán)格,scoped_ptr對(duì)象一旦獲取對(duì)象的管理權(quán)就將一直占用,不能在進(jìn)行管理權(quán)轉(zhuǎn)移。scoped_ptr像它的名字一樣,只能在起作用域內(nèi)進(jìn)行使用。使用后會(huì)使得代碼相對(duì)簡(jiǎn)單且不會(huì)增加多余操作。
scoped_ptr使用方法:
scoped_ptr使用簡(jiǎn)單,只需要在原來(lái)使用new的地方用scoped_ptr進(jìn)行替換即可,
使用方法如下:
scoped_ptr<string> pStr(new string("hello word"));
操作scoped_ptr指針也很簡(jiǎn)單,使用方式和普通指針一致,如:
//打印指針指向字符串內(nèi)容 cout<<pAtr<<endl; //打印字符長(zhǎng)度 cout<<pAtr->size()<<endl;
需要注意的是:1)此指針對(duì)象會(huì)進(jìn)行自動(dòng)釋放,無(wú)需使用delete進(jìn)行釋放,如果在實(shí)際編程時(shí)使用了delete,編譯器將會(huì)報(bào)錯(cuò),大家不妨可以思考下原因是什么歡迎留言。2)scoped_ptr是不能進(jìn)行賦值、拷貝操作得到,生命周期只限于聲明的作用域內(nèi)。
和auto_ptr指針相比,scoped_ptr的不同點(diǎn)如下:
兩者都不能作為容器元素,但是原因卻不同。auto_ptr是因?yàn)樗陨淼霓D(zhuǎn)義語(yǔ)義,但是scoped_ptr是因?yàn)椴恢С挚截惡蛷?fù)制。
指針?biāo)袡?quán)不同,auto_ptr是可以進(jìn)行轉(zhuǎn)義得到,但是scoped_ptr不能進(jìn)行轉(zhuǎn)義,因?yàn)槠錁?gòu)造和拷貝函數(shù)都是私有的。
1.4 scoped_array
scoped_array和scoped_ptr基本相同,根本區(qū)別是scoped_array是指向數(shù)組的,封裝了new[],彌補(bǔ)了指向數(shù)組的智能指針。
scoped_array使用方法:
scoped_array和scoped_ptr設(shè)計(jì)思想相同,使用方法也基本一致,如下:
scoped_array<int> pIntArray(new int[10]);
使用時(shí)需要注意的是:scoped_array不會(huì)對(duì)數(shù)組范圍進(jìn)行檢查,且不能通過(guò)數(shù)組名+偏移的方式進(jìn)行獲取。
但可以按照以下方式使用:
pIntArray[0]=100; pIntArray[1]=200; 1.5 shared_ptr
shared_ptr已經(jīng)被引入C++標(biāo)準(zhǔn)庫(kù)中,功能強(qiáng)大,可以像普通指針那樣使用,它是引用計(jì)數(shù)型指針,可以被任意的復(fù)制和拷貝。同時(shí)shared_ptr可以被用作容器元素。
可以說(shuō)shared_ptr是C++歷史上實(shí)現(xiàn)智能指針?biāo)惴ㄖ凶罱艹龅拇碜鳌?/p>
shared_ptr使用方法:
shared_ptr指針是最接近原始指針的。他比auto_ptr和scoped_ptr應(yīng)用范圍更廣,幾乎可以百分之百避免程序中的內(nèi)存泄露,但是使用卻又像auto_ptr和scoped_ptr一樣簡(jiǎn)單。
shared_ptr是線程安全的,可以由多個(gè)線程進(jìn)行讀取。
使用方式如下:
int main()
{
? ? //定義一個(gè)指針對(duì)象
? ?shared_ptr<int> pInt(new int);
? ?//對(duì)指針進(jìn)行賦值
? ?*pInt = 100;
? ?cout<<*pInt<<endl;
? ?//調(diào)用shared_ptr重載方法
? ?shared_ptr<int> pInt_cp = pInt;
? ?cout<<*pInt_cp<<endl;
? ?pInt.reset();
? ?assert(!pInt);
? ?return 0;
}如上代碼所示shared_ptr構(gòu)造函數(shù)中依舊使用new的方法創(chuàng)建一個(gè)對(duì)象,但這個(gè)遠(yuǎn)遠(yuǎn)不夠,shared_ptr提供make_shared方法來(lái)創(chuàng)建一個(gè)共享指針對(duì)象,
方式如下:
int main()
{
? ?shared_ptr<string> pStr= make_shared<string>("hello world");
? ?cout<<*pStr<<endl;
? ?shared_ptr<vector<int> > pVec = make_shared<vector<int> >(10,2);
? ?cout<<pVec->size()<<endl;
? ?return 0;
}代碼輸出結(jié)果為:
hello world
10
shared_ptr高級(jí)用法;
shared_ptr 可以保存任意類(lèi)型指針,可以理解成是改指針是泛型的。
shared_ptr<void *>退出作用域后調(diào)用回調(diào)函數(shù),如下:
void fun(void *p){}
shared_ptr<void *> p((void *0),fun);除此之外,shared_ptr還有其它很多高級(jí)用法,如:延時(shí)釋放、包裝成員函數(shù)等,感興趣的話可以自行研究。
1.6 shared_array
shared_array功能和shared_ptr類(lèi)似,根本區(qū)別是包裝了new[]操作符,可以指向數(shù)組,知道引用計(jì)數(shù)為0時(shí)才會(huì)進(jìn)行釋放。
shared_array使用方法:
shared_array是shared_ptr和scoped_array的結(jié)合體。
使用方法如下所示:
int main()
{
? ?int *p = new int[100];
? ?shared_array<int> sp(p);
? ?shared_array<int> sp1=sp;
? ?sp[0]=10;
? ?return 0;
}1.7 weak_ptr弱指針
weak_ptr不具備普通指針的行為,需要和shared_ptr配合使用。主要用于協(xié)助shared_ptr工作,觀測(cè)資源的使用情況。
weak_ptr使用方法:
weak_ptr和shared_ptr共用可以通過(guò)shared_ptr或者weak_ptr對(duì)象構(gòu)造,使用時(shí)不會(huì)產(chǎn)生引用計(jì)數(shù)增加,析構(gòu)時(shí)也不會(huì)導(dǎo)致引用計(jì)數(shù)的減少??梢允褂胾se_count查看引用計(jì)數(shù),也可以使用其等效的方法expired(),如果引用計(jì)數(shù)為0則表示觀測(cè)的對(duì)已經(jīng)不存在了。代碼示例如下:
int main()
{
? ?shared_ptr<int> p(new int(100));
? ?cout<<p.use_count()<<endl;
? ?weak_ptr<int> wp(p);
? ?cout<<wp.use_count()<<endl;
? ?p.reset();
? ?if(!wp.expired())
? ?{
? ? ? ?shared_ptr<int> p1=wp.lock();
? ? ? ?*p1 = 1000;
? ? ? ?cout<<wp.use_count()<<endl;
? ?}
? ?return 0;
}2 總結(jié)
如上,介紹了boost庫(kù)提供的幾種智能指針的方法、定義和使用,實(shí)際編碼時(shí)可以根據(jù)使用場(chǎng)景使用不同的指針,這里尤其要推的是shared_ptr,使用它幾乎可以解決我們遇到的所有使用場(chǎng)景。當(dāng)然boost還提供了一種侵入式智能指針,但是因?yàn)槠涫褂靡髧?yán)格,官方已經(jīng)不再推薦使用,所以,本文也沒(méi)有進(jìn)行介紹。
到此這篇關(guān)于C++內(nèi)存管理介紹的文章就介紹到這了,更多相關(guān)C++內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于C++詳解數(shù)據(jù)結(jié)構(gòu)(附帶例題)
數(shù)據(jù)結(jié)構(gòu)作為每一個(gè)IT人不可回避的問(wèn)題,本文基于C++編寫(xiě),下面這篇文章主要給大家介紹了關(guān)于數(shù)據(jù)結(jié)構(gòu)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
C++數(shù)據(jù)結(jié)構(gòu)之list詳解
list是一種序列式容器。list容器完成的功能實(shí)際上和數(shù)據(jù)結(jié)構(gòu)中的雙向鏈表是極其相似的,list中的數(shù)據(jù)元素是通過(guò)鏈表指針串連成邏輯意義上的線性表,也就是list也具有鏈表的主要優(yōu)點(diǎn),即:在鏈表的任一位置進(jìn)行元素的插入、刪除操作都是快速的2021-11-11
詳解C++中的內(nèi)存同步模式(memory order)
這篇文章主要介紹了C++中的內(nèi)存同步模式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單酒店管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單酒店管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C++實(shí)現(xiàn)的分布式游戲服務(wù)端引擎KBEngine詳解
這篇文章主要詳細(xì)介紹了C++實(shí)現(xiàn)的分布式游戲服務(wù)端引擎KBEngine的概念以及使用方法,非常的實(shí)用,有需要的小伙伴可以參考下2015-03-03
C++項(xiàng)目實(shí)戰(zhàn)之makefile使用
這篇文章主要介紹了C++項(xiàng)目實(shí)戰(zhàn)之makefile使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05

