一、若是所建立的類存在指針成員,通常都須要定義拷貝構造函數、拷貝賦值構造函數與析構函數;
二、new與delete的底層過程;ios
代碼內容以下:c++
#ifndef CLASS_H #define CLASS_H #include<iostream> using std::cout; using std::endl; class data_class { public: data_class(double,double); ~data_class(); double Get_data1() { return data1; } void Set_data1(double data1) { data1 = data1; }; void Set_data2(double data2) { data2 = data2; } double Get_data2() { return data2; } private: double data1; double data2; }; data_class::data_class(double data1 = 0,double data2=0):data1(data1),data2(data2) { } data_class::~data_class() { cout << "調用data_class析構函數" << endl; } class class_for_copy_test { public: class_for_copy_test(data_class*);//參數初始化; class_for_copy_test(const class_for_copy_test&); class_for_copy_test(const class_for_copy_test*); class_for_copy_test& operator =(const class_for_copy_test&); ~class_for_copy_test(); private: data_class* data_point; }; class_for_copy_test::class_for_copy_test(data_class* point_new_out =NULL) { data_class* point_new; if(point_new_out ==NULL) point_new = new data_class();//傳入爲空指針 else point_new = new data_class(point_new_out->Get_data1(),point_new_out->Get_data2());//傳入爲空指針 data_point = point_new;//傳入指針非空 } class_for_copy_test::class_for_copy_test(const class_for_copy_test& same_class) { data_class* new_data = new data_class(same_class.data_point->Get_data1(),same_class.data_point->Get_data2()); this->data_point = new_data; } class_for_copy_test::class_for_copy_test(const class_for_copy_test* same_class) { data_class* new_data; if (same_class == NULL) { cout << "傳入爲空指針" << endl; new_data = new data_class(0, 0); } else new_data = new data_class(same_class->data_point->Get_data1(),same_class->data_point->Get_data2()); this->data_point = new_data; }; class_for_copy_test& class_for_copy_test::operator =(const class_for_copy_test& other_object) { if (other_object.data_point == this->data_point) return *this; delete this->data_point; data_class* new_data = new data_class(other_object.data_point->Get_data1(), other_object.data_point->Get_data2()); this->data_point = new_data; return *this; }; class_for_copy_test::~class_for_copy_test() { cout << "調用class_for_copy_test析構函數" << endl; delete this->data_point;//析構內部指針 } #endif // !CLASS_H
在類class_for_copy_test中定義一個成員變量data_class的指針,data_class類包含兩個double類型的成員,其中該函數的拷貝構造函數爲:數組
class_for_copy_test::class_for_copy_test(const class_for_copy_test& same_class) { data_class* new_data = new data_class(same_class.data_point->Get_data1(),same_class.data_point->Get_data2()); this->data_point = new_data; }
因爲class_for_copy_test存在默認構造函數class_for_copy_test::class_for_copy_test(data_class* point_new_out =NULL),因此在拷貝構造函數中不用檢查same_class是否爲NULL,所以直接從新申請一塊內存將same_class的值拷貝到新的申請的內存中便可。這樣作的目的是防止淺拷貝的產生使得通過拷貝後其成員變量data_point值同樣,使得最後在析構的時候兩次析構相同的內存區域。
其拷貝賦值構造函數:函數
class_for_copy_test& class_for_copy_test::operator =(const class_for_copy_test& other_object) { if (other_object.data_point == this->data_point) return *this; delete this->data_point; data_class* new_data = new data_class(other_object.data_point->Get_data1(), other_object.data_point->Get_data2()); this->data_point = new_data; return *this; };
與拷貝構造函數不一樣的是,拷貝賦值構造函數須要進行如下三步:
一、檢查是否爲自我拷貝;
二、釋放被賦值對象的data_point指針所指空間;
三、開闢新的內存空間而且使用內部data_point指針指向該內存;
須要檢測是否爲自我賦值的緣由是如果自我賦值,則因爲先調用了delete this->data_point,所以右值會被釋放,那麼賦值就失敗了。
在析構函數中須要釋放程序鎖開闢的內存區域:this
class_for_copy_test::~class_for_copy_test() { cout << "調用class_for_copy_test析構函數" << endl; delete this->data_point;//析構內部指針 }
至此完成了包含指針的類的設計,特別注意的是這個類使用了深拷貝而不能使用默認拷貝構造函數與拷貝賦值構造函數所默認的淺拷貝的設計。spa
在c++中使用new分配的內存位於棧內存中,若是一個對象complex包含兩個double的成員對象,那麼在內存中使用new complex會分配多少內存呢?new會首先調用一個malloc sizeof(complex)來獲知對象須要的內存空間,而後使用對象的構造函數進一步初始化內存,所以就有了後續的placement new。
在32位機器上使用debug模式,IDE爲vc中,其內存分佈爲:debug
因爲一個double所佔內存爲4字節(32位),分配三個對象須要(8*3)字節的數據內存,在Debuger模式下圖中內存的分佈順序爲:
一、使用Debuger模式還須要32字節的Debuger頭文件;
二、隨後的3表示初始化對象數組的個數(便於肯定屢次調用析構函數的次數等),4個字節;
三、分配對象實際須要的內存數,(8*3)字節;
四、no man land,4個字節,不知道幹嗎用的。。。;
五、cookis內存,其主要記錄當前內存區塊的狀態,如圖中須要的內存大小爲72字節(包含了首尾兩個cookis),而使用了內存對齊的話其應該分配16的倍數字節個內存,所以須要分配80字節,80字節使用16進製表示爲50H,可是當前的內存是給出去的,因此末尾置1,獲得51H,隨後將其填充到內存的首尾;
六、填充內存;
在非Debuger模式下消除了Debuger的首部內存,同時也消除了no man land的內存,可是依舊須要cookis與字節對齊。
在進行delete時候就須要注意了,如圖所示:
能夠看到若是所分配的對象中包含指向其餘內存區塊的指針,那麼實際上應該屢次調用析構函數纔可以防止內存泄漏,可是若是使用了new[]卻使用了delete。
那麼對於不包含指正對象的類而言,實際上是沒有影響的(指的是回收內存方面),由於調用一次析構函數與調用三次的後果是同樣的,自己的內存空間在使用delete的free釋放後就釋放了全部的分配的內存(我使用VS會報錯);可是對於包含指針成員的對象而言,僅僅調用了一次析構函數會使得指針成員所指向的除去第一個對象的內存空間所有泄漏,這是一種很危險的作法。設計