1. 程式人生 > 其它 >C++學習筆記 2

C++學習筆記 2

C++學習筆記2

面向物件

含指標的類string

data怎麼存?

用指標不錯,總不能一個個儲存吧

拷貝構造、拷貝複製

建構函式接受的引數是自己這個類的物件(引用),為拷貝構造。

=過載,引數是自己這個類的物件,為拷貝複製。

String(const String& str);                    
String& operator=(const String& str); 

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}

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;
}

String s1("hello");
String s2(s1);
String s2=s1;//與上一行一個意思,看函式實現也差不多

只要寫的是帶指標的類,就必須完成這兩個函式。對於不帶指標的類complex,不寫也一樣,編譯器會忠實的完全bit複製過來,已經很好了。但是指標不能複製,空間應該重新分配。

淺拷貝就是純bit複製,造成記憶體洩露和別名alias;深拷貝就是把指標指的內容重新建立並賦值。

這裡的建構函式,拿到外部去實現了。

建構函式

String(const char* cstr=0);

#include <cstring>
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';
   }
}

String* p=new String(“hello”)

解構函式

寫法類似建構函式,與類同名,且前方有個 ~.

~String();


inline
String::~String()
{
   delete[] m_data;
}

當這個類的物件死亡時、離開作用域時,會被呼叫(自動)。

有指標的類,要做解構函式處理動態分配的空間(手動)。

用指標動態分配的物件,也要手動delete。

輸出函式

要寫成全域性函式,

#include <iostream>
using namespace std;

ostream& operator<<(ostream& os, const String& str)
{
   os << str.get_c_str();
   return os;
}

char* get_c_str() const {return m_data;}//寫到類裡面

堆Heap和棧Stack,與new關鍵字

記憶體

棧是存在於一個函式作用域的一塊記憶體空間,用於存放參數、返回地址等。

堆是由作業系統提供的一塊全域性記憶體空間,程式可以動態分配從其中獲得一定的大小。

Complex c1(1,2);
Complex* c2=new Complex(2,3);

棧裡的內容,函式結束後(離開作用域)就會被釋放。會呼叫解構函式。又稱為 auto object,因為會自動釋放。

如果是 static object,直到整個程式結束後才會釋放。

如果是 global object,有點類似static,也是程式結束才會釋放。

堆裡的內容,必須手動釋放。一個new對應一個delete,其生命在delete後結束。如果不釋放,會記憶體洩露,其嚴重性在於:當作用域結束後,指標的生命結束了,作用域之外沒辦法使用指標,對這一塊的記憶體就失去了控制。

new與delete

new是先分配memory,再呼叫建構函式ctor。可以分為下述步驟:

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

Complex* pc;
void mem=operator new(sizeof(Complex));//operator new其實是一個名字特別的函式,下一層就是malloc。
pc=static_cast<Complex*>(mem);//指標的型別轉換
pc->Complex::Complex(1,2);//建構函式

建構函式是個成員函式,現在是由指標呼叫,因此相當於指標是建構函式裡的 this,指向記憶體空間的起點。然後呼叫建構函式複製。

delete是先呼叫解構函式的dtor,再釋放memory。

String* ps = new String("Hello");
delete ps;


String::~String(ps);//釋放字串裡面的動態分配的空間
operator delete(ps);//下一層是free

記憶體塊大小

vc給分配的記憶體空間一定是16B的倍數。

在debug下。會包含很多除錯資訊,以及cookie(用於記錄長度和分配狀況,提供給malloc和free用)。還可能有補充為16B整數倍的padding。

在release下,沒有除錯資訊,別的一樣。

有中括號的new和delete (array new/delete)

要互相搭配,否則會出錯。寫法如下:

m_data = new char[strlen(cstr)+1];

delete[] m_data;

動態分配的陣列中,在資料前會有一個整數記錄陣列容量。(VC)具體問題如下:

刪除整個陣列沒問題,因為大小寫在cookie裡;但是除了第0個元素,後面的元素的沒有呼叫解構函式,這就造成了記憶體洩露。(當然是因為後面類的變數有指標)