本周學習了帶指針類的寫法
帶指針類中的三個特殊函數
1.拷貝構造函數:又稱復制構造函數,是一種特殊的構造函數,它由編譯器調用來完成一些基于同一類的其他對象的構建及初始化。其唯一的形參必須是引用,但并不限制為const,一般普遍的會加上const限制。此函數經常用在函數調用時用戶定義類型的值傳遞及返回。拷貝構造函數要調用基類的拷貝構造函數和成員函數。如果可以的話,它將用常量方式調用,另外,也可以用非常量方式調用。
2.拷貝賦值函數:即對“=”重載。由于"="的缺省操作只是將成員變量的值相應復制,而對象內包含指針,將造成不良后果:指針的值被丟棄了,但指針指向的內容并未釋放。指針的值被復制了,但指針所指內容并未被復制。所以需要對“=”進行重載。
3.析構函數:析構函數(destructor)與構造函數相反,當對象結束其生命周期時(例如對象所在的函數已調用完畢),系統自動執行析構函數。析構函數往往用來做“清理善后”的工作(例如在建立對象時用new開辟了一片內存空間,應在退出前在析構函數中用delete釋放)。
析構函數名應與類名相同,只是在函數名前面加一個位取反符~,例如~string( ),以區別于構造函數。它不能帶任何參數,也沒有返回值(包括void類型)。只能有一個析構函數,不能重載。如果用戶沒有編寫析構函數,編譯系統會自動生成一個缺省的析構函數(即使自定義了析構函數,編譯器也總是會為我們合成一個析構函數,并且如果自定義了析構函數,編譯器在執行時會先調用自定義的析構函數再調用合成的析構函數),它也不進行任何操作。所以許多簡單的類中沒有用顯示的析構函數。
堆、棧與內存管理
棧(stack),是存在與某作用域(scope)的一塊內存空間(memory space)。例如當你調用函數,函數本身即會形成一個棧用來放置它所接收的參數,以及返回地址。在函數體(function body)內聲明的任何變量,其所用的內存塊都取自上述棧。
堆(heap或system heap),是指由操作系統提供的一塊global內存空間,程序可動態分配(dynamic allocated)從某中獲得若干區塊(blocks)。
在構造函數中使用new時應注意:
1.如果在構造函數中使用new來初始化指針成員,則應在析構函數中使用delete
2.new和delete必須相互兼容。new對應于delete,new[]對應于delete []
3.如果有多個構造函數,則必須以相同的方式使用new,要么都帶中括號,要么都不帶。因為只有一個析構函數,所有的構造函數都必須與它兼容
stack objects的生命周期
class T { } ;
...
{? ? ? ? T t1(1,2); ? ? ?}
t1便是stack object,其生命在作用域(scope)結束之際結束。這種作用域內的object又稱為auto object,因為它會被“自動”清理。
static local objects的生命周期
class T { } ;
...
{? ? ? ? static T t2(1,2); ? ? ? ??}
t2便是static object,其生命在作用域結束之后仍存在,直到整個程序結束。
global objects的生命周期
class T { ... };
...
T t3(1,2);
int main()
{ ? ?... ? ??}
t3便是global object,其生命在整個程序結束之后才結束。其可視為一種static object。
heap objects的生命周期
class T {...};
...
{
? ? T* p = new T;
? ? ...
? ? delete p;
}
p所指的便是heap object,其生命在它被delete之際結束。
如果沒有delete,會出現內存泄漏。