C++動(dòng)態(tài)內(nèi)存與智能指針

C++動(dòng)態(tài)內(nèi)存

了解動(dòng)態(tài)內(nèi)存在 C++ 中是如何工作的是成為一名合格的 C++ 程序員必不可少的。C++ 程序中的內(nèi)存分為兩個(gè)部分:

  • 棧:在函數(shù)內(nèi)部聲明的所有變量都將占用棧內(nèi)存。
  • 堆:這是程序中未使用的內(nèi)存编丘,在程序運(yùn)行時(shí)可用于動(dòng)態(tài)分配內(nèi)存。
    很多時(shí)候,您無(wú)法提前預(yù)知需要多少內(nèi)存來(lái)存儲(chǔ)某個(gè)定義變量中的特定信息,所需內(nèi)存的大小需要在運(yùn)行時(shí)才能確定矛纹。

在 C++ 中,您可以使用特殊的運(yùn)算符為給定類型的變量在運(yùn)行時(shí)分配堆內(nèi)的內(nèi)存光稼,這會(huì)返回所分配的空間地址或南。這種運(yùn)算符即 new 運(yùn)算符。

如果您不再需要?jiǎng)討B(tài)分配的內(nèi)存空間艾君,可以使用 delete 運(yùn)算符采够,刪除之前由 new 運(yùn)算符分配的內(nèi)存。

new和delete運(yùn)算符

new data-type

在這里冰垄,data-type 可以是包括數(shù)組在內(nèi)的任意內(nèi)置的數(shù)據(jù)類型蹬癌,也可以是包括類或結(jié)構(gòu)在內(nèi)的用戶自定義的任何數(shù)據(jù)類型。讓我們先來(lái)看下內(nèi)置的數(shù)據(jù)類型虹茶。例如逝薪,我們可以定義一個(gè)指向 double 類型的指針,然后請(qǐng)求內(nèi)存蝴罪,該內(nèi)存在執(zhí)行時(shí)被分配翼闽。我們可以按照下面的語(yǔ)句使用 new 運(yùn)算符來(lái)完成這點(diǎn):

double* pvalue  = NULL; // 初始化為 null 的指針
pvalue  = new double;   // 為變量請(qǐng)求內(nèi)存

malloc() 函數(shù)在 C 語(yǔ)言中就出現(xiàn)了,在 C++ 中仍然存在洲炊,但建議盡量不要使用 malloc() 函數(shù)。new 與 malloc() 函數(shù)相比尼啡,其主要的優(yōu)點(diǎn)是暂衡,new 不只是分配了內(nèi)存,它還創(chuàng)建了對(duì)象崖瞭。

在任何時(shí)候狂巢,當(dāng)您覺得某個(gè)已經(jīng)動(dòng)態(tài)分配內(nèi)存的變量不再需要使用時(shí),您可以使用 delete 操作符釋放它所占用的內(nèi)存书聚,如下所示:

delete pvalue;        // 釋放 pvalue 所指向的內(nèi)存

new和malloc有什么不同

new 的功能是在堆區(qū)新建一個(gè)對(duì)象唧领,并返回該對(duì)象的指針藻雌。所謂的【新建對(duì)象】的意思就是,將調(diào)用該類的構(gòu)造函數(shù)斩个,因?yàn)槿绻粯?gòu)造的話胯杭,就不能稱之為一個(gè)對(duì)象。而 malloc 只是機(jī)械的分配一塊內(nèi)存受啥,如果用 mallco 在堆區(qū)創(chuàng)建一個(gè)對(duì)象的話做个,是不會(huì)調(diào)用構(gòu)造函數(shù)的。嚴(yán)格說(shuō)來(lái)用 malloc 不能算是新建了一個(gè)對(duì)象滚局,只能說(shuō)是分配了一塊與該類對(duì)象匹配的內(nèi)存而已居暖,然后強(qiáng)行把它解釋為【這是一個(gè)對(duì)象】,按這個(gè)邏輯來(lái)藤肢,也不存在構(gòu)造函數(shù)什么事太闺。同樣的,用 delete 去釋放一個(gè)堆區(qū)的對(duì)象嘁圈,會(huì)調(diào)用該對(duì)象的析構(gòu)函數(shù)省骂。用 free 去釋放一個(gè)堆區(qū)的對(duì)象,不會(huì)調(diào)用該對(duì)象的析構(gòu)函數(shù)丑孩。
做個(gè)簡(jiǎn)單的實(shí)驗(yàn)即可明了:

#include <iostream>
#include <malloc.h>

class TEST
{
private:
    int num1;
    int num2;
public:
    TEST()
    {
        num1 = 10;
        num2 = 20;
    }
    void Print()
    {
        std::cout << num1 << " " << num2 << std::endl;
    }
};

int main(void)
{
    // 用malloc()函數(shù)在堆區(qū)分配一塊內(nèi)存空間冀宴,然后用強(qiáng)制類型轉(zhuǎn)換將該塊內(nèi)存空間
    // 解釋為是一個(gè)TEST類對(duì)象,這不會(huì)調(diào)用TEST的默認(rèn)構(gòu)造函數(shù)
    TEST * pObj1 = (TEST *)malloc(sizeof(TEST));
    pObj1->Print();

    // 用new在堆區(qū)創(chuàng)建一個(gè)TEST類的對(duì)象温学,這會(huì)調(diào)用TEST類的默認(rèn)構(gòu)造函數(shù)
    TEST * pObj2 = new TEST;
    pObj2->Print();

    return 0;
}
/*
運(yùn)行結(jié)果:

-----------------------------
-842150451 -842150451       |
10 20                       |
請(qǐng)按任意鍵繼續(xù). . .         |
-----------------------------

我們可以看到pObj1所指的對(duì)象中略贮,字段num1與num2都是垃圾值
而pObj2所指的對(duì)象中,字段num1與num2顯然是經(jīng)過(guò)了構(gòu)造后的值
*/

智能指針

動(dòng)態(tài)內(nèi)存的使用很容易出現(xiàn)問題仗岖,因?yàn)榇_保在正確的時(shí)間釋放內(nèi)存是極其困難的逃延。有時(shí)候我們會(huì)忘記釋放內(nèi)存,在這種情況下就會(huì)產(chǎn)生內(nèi)存泄漏轧拄;有時(shí)候在尚有指針引用內(nèi)存的情況下我們就釋放了它揽祥,在這種情況下就會(huì)產(chǎn)生引用非法內(nèi)存的指針。

為了更容易地使用動(dòng)態(tài)內(nèi)存檩电,新的標(biāo)準(zhǔn)庫(kù)提供了兩種智能指針類型來(lái)管理動(dòng)態(tài)對(duì)象拄丰。智能指針的行為類似常規(guī)指針,重要的區(qū)別是它負(fù)責(zé)自動(dòng)釋放所指向的對(duì)象俐末。新標(biāo)準(zhǔn)庫(kù)提供的這兩種智能指針的區(qū)別在于管理底層指針的方式:shared_ptr允許多個(gè)指針指向同一個(gè)對(duì)象料按;unique_ptr則獨(dú)占所指向的對(duì)象。標(biāo)準(zhǔn)庫(kù)還定義了一個(gè)名為weak_ptr的伴隨類卓箫,它是一種弱引用指向shared_ptr所管理的對(duì)象载矿。這三種類型都定義在memory頭文件中。

shred_ptr類

類似vector烹卒,智能指針也是模板闷盔。因此當(dāng)我們創(chuàng)建一個(gè)智能指針時(shí)弯洗,必須提供額外的信息——指針可以指向的類型。與vector一樣逢勾,我們?cè)诩饫ㄌ?hào)內(nèi)給出類型牡整,之后是所定義的這種智能指針的名字:

shared_ptr<string> p1;        //shared_ptr,可以指向string
shared_ptr<list<int>> p2;     //shard_ptr,可以指向int的list

默認(rèn)初始化的智能指針中保存著一個(gè)空指針。
智能指針的使用方式與普通指針類似敏沉。解引用一個(gè)智能指針返回它指向的對(duì)象果正。如果在一個(gè)條件判斷中使用智能指針,效果就是檢測(cè)它是否為空:

if(p1 && p1->empty())    //如果p1不為空盟迟,檢查它是否指向一個(gè)空string
  *p1 = "hi";            //若果p1指向一個(gè)空string秋泳,解引用p1,將一個(gè)新值賦予string
shared_ptr和unique_ptr 都支持的操作
shared_ptr<T> sp 空智能指針攒菠,可以指向類型為T的對(duì)象
unique_ptr<T> up
p 將p用作一個(gè)條件判斷迫皱,若p指向一個(gè)對(duì)象,則為true
*p 解引用p辖众,獲得它所指的對(duì)象
p-> 等價(jià)于(*p).mem
p.get() 返回p中所保存的指針.要小心,若智能指針釋放了其對(duì)象,返回的指針?biāo)赶虻膶?duì)象也就消失了
swap(p,q) 交換p和q中的指針
p.swap(q)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卓起,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子凹炸,更是在濱河造成了極大的恐慌戏阅,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啤它,死亡現(xiàn)場(chǎng)離奇詭異奕筐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)变骡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門离赫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人塌碌,你說(shuō)我怎么就攤上這事渊胸。” “怎么了台妆?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵翎猛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我接剩,道長(zhǎng)办成,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任搂漠,我火速辦了婚禮,結(jié)果婚禮上某弦,老公的妹妹穿的比我還像新娘桐汤。我一直安慰自己而克,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布怔毛。 她就那樣靜靜地躺著员萍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拣度。 梳的紋絲不亂的頭發(fā)上碎绎,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音抗果,去河邊找鬼筋帖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冤馏,可吹牛的內(nèi)容都是我干的日麸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼逮光,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼代箭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起涕刚,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嗡综,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后杜漠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體极景,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年碑幅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了戴陡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慢宗。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡轴合,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尔艇,到底是詐尸還是另有隱情裹赴,我是刑警寧澤喜庞,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站棋返,受9級(jí)特大地震影響延都,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜睛竣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一晰房、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦殊者、人聲如沸与境。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)摔刁。三九已至,卻和暖如春海蔽,著一層夾襖步出監(jiān)牢的瞬間共屈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工党窜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拗引,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓刑然,卻偏偏與公主長(zhǎng)得像寺擂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泼掠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容