一、Big Three
第二周是 class with pointer members的内容,用 string 来讲解。
对于带指针的类有关键三个特殊函数,Big Three(三巨头)
- 拷贝构造函数
- 拷贝赋值函数
- 析构函数
对于带指针的类,存储的数据是指针,在构造函数要完成申请内存和拷贝字符串。析构函数完成内存的释放。
二、拷贝构造函数和拷贝赋值函数
2.1 浅拷贝与深拷贝
对于字符串常量,C++用独立的内存区域存储,简单赋值字符串指针会使两个对象的指针成员指向相同的地址,这就是浅拷贝,可能带来内存泄露。在拷贝赋值运算符重载函数中要清理内存,并且重新申请新的内存空间,这就是深拷贝。
//拷贝赋值运算符
String& operator=(const String& str)
{
m_data=s.m_data;//指针变量直接赋值,浅拷贝
}
2.2 拷贝赋值函数
必须注意的是拷贝赋值函数要检测自我赋值,因为拷贝赋值函数的工作是,先释放自身指针指向的内存,再重新申请内存,进行赋值。自我赋值会先释放自己的数据部分,在接下的步骤产生未定义行为。
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;
}
2.3 析构函数
先析构,析构对象,再进入函数体
~String() //第一步析构对象
{
delete[] m_data;//第二步进入函数体,释放指针指向的内存空间
}
二、array new 和 array delete
我们在生成数组和清理数组用到的就是array new 和 array delete
char* str=new char[12];//array new
delete[] str;//array delete
若是数组没有采用array delete 将会产生内存泄露。
数组在内存上存储上包括一个计数部分和数据部分,在图中为3。没有采用 array delete ,在析构时只调用一次析构函数,所以另外两个指针指向的内存空间没有得到释放,造成了内存泄露。
所以出乎意料的事,不带指针的类生成的数组,不用 array delete 也不会造成了内存泄露,但是对于每个程序员都要警惕这种错误,每次 array new 都要采用 array delete。