C++如何設(shè)計一個類2(含指針的類)

C++如何設(shè)計一個類2(含指針的類)


本文預(yù)覽:

  • BigThree:拷貝構(gòu)造补憾、拷貝復(fù)制陵吸、析構(gòu)
  • Stack(棧) Heap(堆)及生命周期
  • new delete 操作符內(nèi)部實現(xiàn)
  • 物理內(nèi)存模型 in VC

BigThree:拷貝構(gòu)造术陶、拷貝復(fù)制莱褒、析構(gòu)

帶有指針的類必須要有拷貝構(gòu)造右遭、拷貝復(fù)制

C++ STL中String的實現(xiàn)是典型的帶指針類茵宪,成員只有一根char類型的指針蟹倾,為什么不用char類型的數(shù)組,這個考量在于猖闪,我們不能確定用戶創(chuàng)建的字符串到底有多少個字符鲜棠,數(shù)組在分配內(nèi)存空間的時候必須是確定的,多了造成浪費培慌,少了空間不足豁陆,所以數(shù)組不適合這樣的需求。使用指針的好處在于吵护,我們是動態(tài)分配的內(nèi)存空間盒音,大小可控。

  • 接口設(shè)計
class String{
public:
   String(const char* cstr=0);                     
   String(const String& str);             //拷貝構(gòu)造              
   String& operator=(const String& str);  //拷貝復(fù)制         
   ~String();                             //析構(gòu)       
   char* get_c_str() const { return m_data; }
private:
    char* m_data;   
};
  • 構(gòu)造和析構(gòu)函數(shù)的實現(xiàn)

我們在每一個函數(shù)定義上面加了inline馅而,這樣是否合適祥诽,有人說復(fù)雜的函數(shù)加了inline多此一舉,是的瓮恭,因為是否是inline這是由編譯器決定的雄坪,我們可以把所有的成員函數(shù)都加上inline,這樣寫是沒有問題的屯蹦,至于是不是维哈,讓編譯器去決定

#include <cstring>      //使用C的函數(shù)

inline
String::String(const char* cstr)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}


inline
String::~String()
{
   delete[] m_data;     //注意,析構(gòu)函數(shù)delete動態(tài)分配的數(shù)組
}

  • 拷貝構(gòu)造函數(shù)的實現(xiàn)

根據(jù)傳入的字符串長度開辟相同大小的內(nèi)存空間登澜,然后執(zhí)行拷貝阔挠,由于包含‘\0’結(jié)束符,所以長度需要加1

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];   //m_data雖然是private的脑蠕,同類之間的對象互為friend
   strcpy(m_data, str.m_data);
}

  • 拷貝復(fù)制
  1. 從右值復(fù)到左值购撼,清空左值之前的數(shù)據(jù),然后開辟新的內(nèi)存空間谴仙,執(zhí)行拷貝
  2. 自檢為什么是必須的份招,當(dāng)是同一個對象的時候,而沒有自檢狞甚,那么會發(fā)生什么锁摔?
    兩個指針指向同一塊內(nèi)存空間,這一塊內(nèi)存空間先delete掉了哼审,再取的時候另一個就變成了野指針
inline
String& String::operator=(const String& str)
{
   if (this == &str)        //自檢不是多余的谐腰,一定要有
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

Stack(棧) Heap(堆)及生命周期

  • Stack

Stack 是存在于某作用域的一塊內(nèi)存空間孕豹。例如當(dāng)你調(diào)用一個函數(shù),函數(shù)本身就會形成一個stack十气,用來存放接收的參數(shù)以及返回地址励背。在函數(shù)本體內(nèi)聲明的任何變量,其所使用的內(nèi)存塊都取自上述 Stack

  • Heap

Heap *或者叫做默認(rèn)System Heap砸西, 是指由操作系統(tǒng)提供的一塊global內(nèi)存空間叶眉,程序可動態(tài)分配,從中獲取若干區(qū)塊(blocks) *

Stack objects的生命期

  • 分析一段代碼
class Complex {...};
...
Complex a3(5,6);

int main()
{
    Complex a1(1,2);    //a1所占用的內(nèi)存來之stack
    static Complex a2(1,3);
    Complex* p = new Complex(2,3); //Complex(2,3)是個臨時對象芹枷,它所占用的內(nèi)存是以new自Heap動態(tài)分配獲得衅疙,并由p指向
}
  • Stack Objects的生命期

上述代碼示例中,a1便是所謂的Stack Object鸳慈, 其生命在作用域結(jié)束之際結(jié)束饱溢。這種作用域的Object,又被稱為auto object走芋, 因為他們會被自動清理绩郎。

  • Stack local Object的生命期

a2便是 static object,它的生命在作用域結(jié)束之后仍然存在翁逞,直到整個程序結(jié)束肋杖。

  • global objects的生命期

a3便是所謂的 global object,其生命在整個程序結(jié)束之后才結(jié)束挖函,也可以把它理解為一種static兽愤,其作用域是整個程序

Heap Objects的生命期

  • 代碼
class Complex {...};
...
{
    Complex* p = new Complex();
    
    delete p;
}

p所指的便是Heap Object,其生命期在被deleted之際結(jié)束挪圾。如果不寫delete p浅萧,會出現(xiàn)內(nèi)存泄漏,p所指向的Heap object仍然存在哲思,但p的生命期結(jié)束了洼畅,作用域外再也看不到p了,也就沒有機(jī)會delete p了棚赔。

new delete操作符內(nèi)部實現(xiàn)

內(nèi)存分配這塊非常重要帝簇,其分析的內(nèi)存模型在很多資料上都是找不到的,內(nèi)存模型是基于VC的靠益,其他編譯器也應(yīng)該大同小異吧丧肴。

new:先分配memory,再調(diào)用ctor()

  • 不包含指針
new的內(nèi)部實現(xiàn)

new內(nèi)部分解為三個步驟:

  1. 調(diào)用 operator new函數(shù)(內(nèi)部malloc)分配內(nèi)存
  2. 轉(zhuǎn)型
  3. 調(diào)用構(gòu)造函數(shù)胧后,賦初始值
  • 包含指針
帶有指針的new

三個步驟是相同的芋浮,在這個例子里,operator new分配了4個字節(jié)的空間給指針壳快,然后轉(zhuǎn)型纸巷,第三步調(diào)用構(gòu)造的函數(shù)的時候镇草,又動態(tài)分配了6個字節(jié)的空間給hello并把地址返回給指針ps

delete:先調(diào)用析構(gòu),再釋放內(nèi)存

delete的內(nèi)部實現(xiàn)

delete內(nèi)部實現(xiàn)分為兩步:

  • 調(diào)用析構(gòu)函數(shù)
  • operator delete釋放內(nèi)存
帶有指針的delete

物理內(nèi)存塊模型 in VC

  • 動態(tài)內(nèi)存分配的對象
實際內(nèi)存分配

在實際的VC編譯器中瘤旨,一個Complex對象是8個字節(jié)梯啤,需要包含4*2個字節(jié)的cookie(delete回收的時候是根據(jù)cookie來進(jìn)行回收的),一共是16字節(jié)存哲,在調(diào)試模式下因宇,需要額外的32+4個字節(jié)的信息。

  • 動態(tài)內(nèi)存分配的array
動態(tài)內(nèi)存分配的array

Complex數(shù)組連續(xù)分配三個對象空間祟偷,并且多了一個4字節(jié)存放數(shù)組的大小內(nèi)存察滑,在沒有調(diào)試模式下,83 + 42 +4 = 36肩袍,序列化必須是16的倍數(shù),所以婚惫,在實際的內(nèi)存中是48字節(jié)氛赐。String的數(shù)組看起來會更小一點,但是還要在堆里面的內(nèi)存先舷。

  • 為什么array new 一定要搭配 array delete
new[] 搭配 delete[]

這個問題就在于delete[] 會多次調(diào)用析構(gòu)函數(shù)艰管,而不加[]只會調(diào)用一次析構(gòu)函數(shù),所以蒋川,在這個例子中牲芋,最后兩個對象內(nèi)部動態(tài)分配的內(nèi)存是被泄漏了,這個內(nèi)存模型分為兩部分捺球,對象數(shù)組部分和對象動態(tài)內(nèi)存缸浦,他們都是在堆里的,那么我們調(diào)用delete p的時候到底泄漏了多少內(nèi)存呢氮兵?答案是后兩個對象的動態(tài)內(nèi)存裂逐,對象數(shù)組本身的內(nèi)存是delete根據(jù)cookie進(jìn)行釋放的。所以泣栈,如果我的類是沒有指針的卜高,那么我直接調(diào)用delete p是不會造成內(nèi)存泄漏的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末南片,一起剝皮案震驚了整個濱河市掺涛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疼进,老刑警劉巖薪缆,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伞广,居然都是意外死亡矮燎,警方通過查閱死者的電腦和手機(jī)定血,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诞外,“玉大人澜沟,你說我怎么就攤上這事∠恳辏” “怎么了茫虽?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長既们。 經(jīng)常有香客問我濒析,道長,這世上最難降的妖魔是什么啥纸? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任号杏,我火速辦了婚禮,結(jié)果婚禮上斯棒,老公的妹妹穿的比我還像新娘盾致。我一直安慰自己,他們只是感情好荣暮,可當(dāng)我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布庭惜。 她就那樣靜靜地躺著,像睡著了一般穗酥。 火紅的嫁衣襯著肌膚如雪护赊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天砾跃,我揣著相機(jī)與錄音骏啰,去河邊找鬼。 笑死抽高,一個胖子當(dāng)著我的面吹牛器一,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厨内,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼祈秕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了雏胃?” 一聲冷哼從身側(cè)響起请毛,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞭亮,沒想到半個月后方仿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年仙蚜,在試婚紗的時候發(fā)現(xiàn)自己被綠了此洲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡委粉,死狀恐怖呜师,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贾节,我是刑警寧澤汁汗,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站栗涂,受9級特大地震影響知牌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜斤程,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一角寸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忿墅,春花似錦扁藕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帖烘。三九已至亮曹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秘症,已是汗流浹背照卦。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留乡摹,地道東北人役耕。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像聪廉,于是被迫代替她去往敵國和親瞬痘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,728評論 2 351

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

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,513評論 1 51
  • 收集非原創(chuàng)文章板熊,如遇原作者框全,請私聊我,我會表明出處干签! 1--10 1. C++中什么數(shù)據(jù)分配在椊虮纾或堆,靜態(tài)存儲區(qū)以...
    Juinjonn閱讀 4,939評論 0 30
  • 題目類型 a.C++與C差異(1-18) 1.C和C++中struct有什么區(qū)別? C沒有Protection行為...
    阿面a閱讀 7,648評論 0 10
  • const 引用 const 引用是指向 const 對象的引用:const int ival = 1024;co...
    rogerwu1228閱讀 626評論 0 1
  • C語言中內(nèi)存分配 在任何程序設(shè)計環(huán)境及語言中喘沿,內(nèi)存管理都十分重要闸度。在目前的計算機(jī)系統(tǒng)或嵌入式系統(tǒng)中,內(nèi)存資源仍然是...
    一生信仰閱讀 1,153評論 0 2