C++物件導向進階編程(三)

來源:互聯網
上載者:User

標籤:64bit   操作   位元組   debug   解構函式   全域   oid   管理   color   

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

接下來的幾篇文章,我將回憶一下C++的基礎.

C++的由兩部分組成 1.C++語言 2.C++標準庫 本篇文章主要分享我學習C++語言的筆記.

 

本節主要介紹 Big Three 即解構函式,拷貝建構函式,賦值拷貝函數,前面主要圍繞不帶指標的class complex本節中主要圍繞帶指標的String類

前面我說過如果你建立的類不帶有指標,那麼多半你可以不用寫解構函式,但是如果你建立了一個帶指標的類,那麼你必須重寫Big Three

建立一個類

class String{public:                                    String(const char* cstr=0);                        String(const String& str);                       String& operator=(const String& str);            ~String();                                       char* get_c_str() const { return m_data; }private:   char* m_data; //由於帶有指標 ,所以需要重寫解構函式,拷貝構造,賦值拷貝};

 

一.拷貝構造

如下操作會調用拷貝建構函式

String a{"hello"};

 

它的實現為

inlineString::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‘;   }}

 

這個大家都應該理解

 

二.拷貝賦值

下面做賦值拷貝操作

String a{"hello"};String b{"world"};s1 = s2;

 

若果我們使用編譯器內建的賦值拷貝就會發生下面的現象

這樣操作會產生野指標,  因為a和b同時指向 hello  ,沒人指向world

同時如果a和b同時指向同一塊記憶體,如果你刪掉a的話  b指向的記憶體也會被刪掉,這可不是我們想要的

 所以我們必須重寫賦值拷貝函數,下面是正確的賦值拷貝函數

inlineString& String::operator=(const String& str) //拷貝賦值{   if (this == &str) //防止自我賦值  //如果不寫這個判斷,那麼執行帶1的時候,就會先殺掉自己,導致錯誤      return *this;   delete[] m_data; //1釋放自己記憶體   m_data = new char[ strlen(str.m_data) + 1 ];//2.建立新的記憶體   strcpy(m_data, str.m_data); //3.copy   return *this;}

 

賦值拷貝的三個步驟: 1.釋放自身記憶體 2.建立新記憶體 3.copy

注意上面的紅色部分

 三.重寫操作符

因為string類是你新建立的,所有cout不識別你自己建立的類,所以你要重寫一個<<

#include <iostream>using namespace std;ostream& operator<<(ostream& os, const String& str) //如果寫成成員函數調用的時候是這樣 c1 << cout  是不是很難接受啊{   os << str.get_c_str();   return os;}

 

 

四.生命週期

下面我來介紹一個記憶體管理

1.Stack(棧),是存在於某範圍 (scope) 的一一塊記憶體空間 (memory space)。例如當你調用函數,函數本身即 會形成一個 stack 用來放置它所接的參數,以及返回地址

2.Heap, system heap,是指由操作系統提供的 一塊 global 內存空間,程式可動態分配 (dynamic allocated) 從某中獲得若干區塊 (blocks)

例如

String s1{"hello"};//stackString s2 = new String("world");// 動態分配  heapstatic Complex c2(1,2); //static

 

stack 棧 的生命週期在範圍結束之際結束.自動清理

heap 堆 的生命週期在他被調用delete之際結束

static 靜態對象 生命週期會一直存在帶程式結束之際

global 全域對象 其生命在整個程式結束之後 才結束。你也可以把它視為一種 static object,其範圍 是「整個程式」

 

五.記憶體管理

先說一下new 和 delete 的調用過程

1. new:先分配 memory, 再調用 ctor 

 Complex* pc = new Complex(1,2);

 

編譯器會把它翻譯成

void* mem = operator new( sizeof(Complex) ); //分配內存,其內部調用mallocpc = static_cast<Complex*>(mem); //轉型pc->Complex::Complex(1,2); //構造函數 pc->Complex::Complex(1,2);

 

 

2. delete:先調用 dtor, 再釋放 mxemory 

Complex* pc = new Complex(1,2);...delete pc;

 

編譯器轉化為

Complex::~Complex(pc); // 解構函式operator delete(pc);   // 釋放內存 其內部調用feee()

 

下面是說一下動態分配所得的記憶體塊以VC編譯器為例

debug版 complex類內涵兩個double型成員變數(實部虛部)

每格4位元組

是不是感到有些驚訝,在debug版下 我們僅new complex() 到底給我們帶來多少的記憶體呢

頭部和尾部(紅色部分)的00000041是 cookie 是兩個4位元組記憶體  cookie負責標記記憶體 最後一位的1是代表獲得記憶體     如果最後一位是0回收記憶體  4*2 = 8bit

灰色部分是VC分期記憶體是賦予的每塊debug記憶體都會有這塊記憶體 4*8 + 4 = 36bit

綠色部分是我們的conplex       8bit

青色部分是補位部分,因為VC下每一塊記憶體必須是16的倍數

那麼我們new一個complex系統應該分配給 (4*2) + 36 + 8 + (4*3 補位) = 64bit

 

那麼非debug版

 

4*2  + 8 = 16;

下面我們來看一下帶指標的string類

debug版

4+(32+4)+(4*2) = 48

非debug版

4+(4*2) + 4 = 16

可見指標佔用的記憶體小一些

總結

1.帶有指標的class必須重寫Big Three這是一個非常良好的習慣

2.指標更省記憶體

如有不正確的地方請指正

參照<<侯捷 C++物件導向進階編程>>

C++物件導向進階編程(三)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.