一、若是所建立的类存在指针成员,通常都须要定义拷贝构造函数、拷贝赋值构造函数与析构函数;
二、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会报错);可是对于包含指针成员的对象而言,仅仅调用了一次析构函数会使得指针成员所指向的除去第一个对象的内存空间所有泄漏,这是一种很危险的作法。设计